2014-06-27 35 views
1

爲什麼ResourceListFragment中的onCreate方法在方向更改上調用兩次?第一次調用應用程序崩潰後,因爲getActivity()onPostExecute回報null,所以我試圖改變:onCreate方法在方向更改上調用兩次

​​

if(savedInstanceStata == null) 
    new HttpTask(this).execute(""); 

然後在第二個電話savedInstanceState爲空,所以mActivatedPosition總是ListView.INVALID_POSITION。 我在使用佈局別名,因此activity_list被activity_twopane取代。

MainActivity

public class MainActivity extends Activity implements 
    TabListener, OnNavigationListener { 

/** 
* Whether or not the activity is in two-pane mode, i.e. running on a tablet 
* device. 
*/ 
private boolean mTwoPane = false; 
ResourceReservationApp app = (ResourceReservationApp)getApplication(); 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_list); 
    mTwoPane = getResources().getBoolean(R.bool.has_two_panes); 

    if(mTwoPane){ 
    // Set up the action bar to show tabs. 
    final ActionBar actionBar = getActionBar(); 
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 
    final String[] dropdownValues = getResources().getStringArray(R.array.dropdown); 
    for (String item : dropdownValues) 
     actionBar.addTab(actionBar.newTab().setText(item).setTabListener(this));  

    }else{ 
     ActionBar actionBar = getActionBar(); 
     actionBar.setDisplayShowTitleEnabled(false); 
      actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 

      final String[] dropdownValues = getResources().getStringArray(R.array.dropdown); 

      ArrayAdapter<String> adapter = new ArrayAdapter<String>(actionBar.getThemedContext(), 
       android.R.layout.simple_spinner_item, android.R.id.text1, 
       dropdownValues); 

      adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
      actionBar.setListNavigationCallbacks(adapter, this);        
    } 


} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu items for use in the action bar 
    MenuInflater inflater = getMenuInflater(); 
    inflater.inflate(R.menu.activity_item_list, menu); 
    return super.onCreateOptionsMenu(menu); 
} 
@Override 
public void onTabSelected(Tab tab, FragmentTransaction ft) { 

    if(tab.getText().equals("Resources")){ 
     ResourceListFragment fragment = new ResourceListFragment();    
       getFragmentManager().beginTransaction() 
       .replace(R.id.fragment_list, fragment).commit();    
    } 
    if(tab.getText().equals("Reservations")){ 
     ReservationListFragment fragment = new ReservationListFragment();       
       getFragmentManager().beginTransaction() 
       .replace(R.id.fragment_list, fragment).commit();      
    } 
} 
@Override 
public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
    // TODO Auto-generated method stub 

} 
@Override 
public void onTabReselected(Tab tab, FragmentTransaction ft) { 
    // TODO Auto-generated method stub 

} 
@Override 
public boolean onNavigationItemSelected(int itemPosition, long itemId) { 
    final String[] dropdownValues = getResources().getStringArray(R.array.dropdown); 
    if(dropdownValues[itemPosition].equals("Resources")){ 
     ResourceListFragment fragment = new ResourceListFragment(); 
      getFragmentManager().beginTransaction() 
        .replace(R.id.activity_list, fragment).commit(); 
    } 
    if(dropdownValues[itemPosition].equals("Reservations")){ 
     ReservationListFragment fragment = new ReservationListFragment();         
      getFragmentManager().beginTransaction() 
        .replace(R.id.activity_list, fragment).commit(); 
    } 
    return true; 
} 
    } 

activity_list.xml

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/activity_list" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    /> 

ResourceListFragment

public class ResourceListFragment extends ListFragment { 
private boolean mTwoPane =false; 
/** 
* The serialization (saved instance state) Bundle key representing the 
* activated item position. Only used on tablets. 
*/ 
private static final String STATE_ACTIVATED_POSITION = "activated_position"; 
/** 
* The current activated item position. Only used on tablets. 
*/ 
private int mActivatedPosition = ListView.INVALID_POSITION; 

public ResourceListFragment() { 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);   
    mTwoPane = getResources().getBoolean(R.bool.has_two_panes); 
    new HttpTask(this).execute(""); 
} 

@Override 
public void onViewCreated(View view, Bundle savedInstanceState) { 
    super.onViewCreated(view, savedInstanceState); 
    if(mTwoPane){ 
     getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
     if (savedInstanceState != null 
       && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { 
      setActivatedPosition(savedInstanceState 
        .getInt(STATE_ACTIVATED_POSITION)); 
     } 
    }  
} 


@Override 
public void onListItemClick(ListView listView, View view, int position, 
     long id) { 
    super.onListItemClick(listView, view, position, id); 

    // Notify the active callbacks interface (the activity, if the 
    // fragment is attached to one) that an item has been selected. 

    ((ResourceReservationApp)getActivity().getApplication()).setSelectedResource((Resource)(listView.getAdapter().getItem(position))); 
    if (mTwoPane) { 
     // In two-pane mode, show the detail view in this activity by 
     // adding or replacing the detail fragment using a 
     // fragment transaction. 

     setActivatedPosition(position); 

     Bundle arguments = new Bundle(); 
     arguments.putString(ResourceDetailFragment.ARG_ITEM_ID, id+""); 
     ResourceDetailFragment fragment = new ResourceDetailFragment(); 
     fragment.setArguments(arguments); 
     getActivity().getFragmentManager().beginTransaction() 
       .replace(R.id.detail_container, fragment).commit(); 

    } else { 

     // In single-pane mode, simply start the detail activity 
     // for the selected item ID. 
     Intent detailIntent = new Intent(getActivity(), ResourceDetailActivity.class); 
     detailIntent.putExtra(ResourceDetailFragment.ARG_ITEM_ID, id);   
     startActivity(detailIntent); 
    } 

} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    if(mTwoPane) { 
     // Serialize and persist the activated item position. 
     outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); 
     outState.putParcelable("AS",(Parcelable) getActivity()); 
    } 
} 

/** 
* Turns on activate-on-click mode. When this mode is on, list items will be 
* given the 'activated' state when touched. 
*/ 


private void setActivatedPosition(int position) { 
    if(mTwoPane) 
    if (position == ListView.INVALID_POSITION) { 
     getListView().setItemChecked(mActivatedPosition, false); 
    } else { 
     getListView().setItemChecked(position, true); 
    }  
    mActivatedPosition = position; 
} 
private class HttpTask extends AsyncTask<String, Void, List<Resource>> { 
     String message="Received"; 
     ResourceListFragment fragment; 
     ProgressDialog dialog; 


     public HttpTask(ResourceListFragment fragment){ 
      this.fragment=fragment; 

     } 


     @Override 
     protected void onPreExecute() { 
      dialog = ProgressDialog.show(getActivity(), "Loading...", "Please wait...", true); 
     } 



     @Override 
     protected List<Resource> doInBackground(String... credentials) { 
      List<Resource>resources=null; 
      try { 
       resources =ResourceDAO.getResourcesFromService("gataric","gataric"); 
       if(resources== null){ 
        message = "Error occured!"; 
        return resources; 
       }     
      } catch (HttpException e) { 
       message = e.getMessage(); 

      } 
      return resources; 
     }  
     @Override 
     protected void onPostExecute(List<Resource> result) { 
      dialog.dismiss();    
      if(result!=null) 
      fragment.setListAdapter(new ArrayAdapter<Resource>(getActivity(), 
        android.R.layout.simple_list_item_activated_1, 
        android.R.id.text1, result)); 
      fragment.setActivatedPosition(fragment.mActivatedPosition); 
      //Toast.makeText(getActivity().getBaseContext(), message, Toast.LENGTH_LONG).show(); 
     } 
    } 
     } 

activity_twopane.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:layout_marginLeft="16dp" 
android:layout_marginRight="16dp" 
android:baselineAligned="false" 
android:divider="?android:attr/dividerHorizontal" 
android:orientation="horizontal" 
android:showDividers="middle" 
tools:context="com.example.resourcereservation.ResourceListActivity" > 

<FrameLayout 
    android:id="@+id/fragment_list"   
    android:layout_width="0dp" 
    android:layout_height="match_parent" 
    android:layout_weight="1" 
    /> 

<FrameLayout 
    android:id="@+id/detail_container" 
    android:layout_width="0dp" 
    android:layout_height="match_parent" 
    android:layout_weight="3" /> 

回答

1

當您的方向更改時,活動被破壞並重新創建,但在重新創建onSaveInstanceState()之前被調用。因此請將您的數據保存在onSaveInstanceState()方法中。然後您可以在onCreate()onRestoreInstanceState()期間恢復狀態。 看到this

+1

你正在描述行爲,但你錯過了他的問題。他有一個AsyncTask。更改方向會破壞活動,但不會取消當時正在運行的任何線程或AsyncTasks,因爲這樣做可能會使整個系統處於損壞狀態(例如文件可能被寫入一半)。使用多線程的代碼需要非常仔細地編寫代碼,以免使用任何類級別的變量(尤其是用戶級別的變量),或者需要關閉旋轉行爲時的破壞。通常是第二個。它唯一有用的,如果你有不同的景觀和肖像佈局。 –

0

你原來的問題:

爲什麼裏面ResourceListFragment onCreate方法調用了兩次方向上的變化?

是的,我偶爾看到了這個,並想知道爲什麼。看到這裏特德·霍普的答案(而不是接受一個):

onCreate(...) is called twice after the device is rotated

您的問題:

禁用取向的改變不被認爲是很好的做法:

How do I disable orientation change on Android?

正如我確定你意識到,你需要像這樣inPostExecute

if (getActivity() != null){ 
    ... 
}