问题
I have gone through so many other similar questions but none solve my problem. One of the uses of Fragments (apparently) is to persist a state. I have a State array called arrState that I have wrapped in a headless fragment called StateFragment.
public class StateFragment extends Fragment {
public static ArrayList<Character> arrState;
protected ActMainGame mActivity = null;
private Character crtX;
public static final String TAG = "StateFragment";
@Override
public void onAttach(Activity activity) {
Log.d(StateFragment.TAG, "StateFragment: onAttach");
super.onAttach(activity);
mActivity = (ActMainGame) activity;
}
@Override
public void onCreate(Bundle b) {
Log.d(StateFragment.TAG, "StateFragment: onCreate");
super.onCreate(b);
setRetainInstance(true);
}
public void setToX() {
arrState = new ArrayList<Character>();
for (int i = 0; i < 9; i++) {
arrState.add(crtX);
}
}
I have an Activity called ActMainGame that fills the array arrState with Xs.
public class ActMainGame extends Activity {
// Fragments
private StateFragment mStateFragment = null;
private static final String TAG_FRAGMENT = "state_fragment";
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(StateFragment.TAG, "ActMainGame: onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.main_game);
// Add Headless Fragment (if not already retained)
FragmentManager FM = getFragmentManager();
mStateFragment = (StateFragment) FM.findFragmentByTag(TAG_FRAGMENT);
if (mStateFragment == null) {
Log.d(StateFragment.TAG, "++ Existing fragment not found. ++");
mStateFragment = new StateFragment();
FM.beginTransaction().add(mStateFragment, TAG_FRAGMENT).commit();
} else {
Log.d(StateFragment.TAG, "++ Existing fragment found. ++");
}
}
@Override
public void onStart() {
super.onStart();
if (D) Log.d(StateFragment.TAG, "ActMainGame: ON START");
mStateFragment.setToX();
}
I have set up logging on the major lifecycle events of both classes. What I expect is that on doing an orientation change that the main activity gets rebuilt but is able to find the fragment (withs it state array containing 9 Xs). Sure enough the fragment is not destroyed but the activity cannot find the persisting fragment via the line:
mStateFragment = (StateFragment) FM.findFragmentByTag(TAG_FRAGMENT);
And therefore creates a new fragment.
Here is the result of the debugging:
++ Existing fragment not found. ++
StateFragment: onAttach
StateFragment: onCreate
ActMainGame: ON START
ActMainGame: onResume
<Orientation change done here>
ActMainGame: onPause
ActMainGame: onStop
StateFragment: onDetach
ActMainGame: onDestroy
ActMainGame: onCreate
++ Existing fragment not found. ++
StateFragment: onAttach
StateFragment: onCreate
ActMainGame: ON START
ActMainGame: onResume
I am well aware that there are other ways to persist a state variable but I want to do it the "fragment way".
回答1:
I finally resolved this! It is a MAJOR bug in Eclipse!! When you create a new Android Application Project in Eclipse, the wizard allows you to start with an actionbar. If you do this and also select Navigation Type "Action Bar Spinner" the wizard creates among other things the following code by default:
@Override
public void onSaveInstanceState(Bundle outState) {
// Serialize the current dropdown position.
outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar()
.getSelectedNavigationIndex());
}
This is very kind of said wizard but there is a huge problem! There is no call to super!! The code works perfectly well in most circumstances BUT if you want to persist a fragment for your activity using SetRetainInstance(true) you need to add the "super" in as follows or it will not detect the fragment when your activity recreates.
Should be:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Serialize the current dropdown position.
outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar()
.getSelectedNavigationIndex());
}
Hope this saves someone else the days it has cost me!
来源:https://stackoverflow.com/questions/23362327/how-can-we-retain-a-simple-state-array-across-configuration-changes-using-headle