@act262
2017-05-24T14:19:32.000000Z
字数 3421
阅读 1650
Android
一般使用的Fragment方式
FragmentManager manager = getFragmentManager();FragmentTransaction transaction = manager.beginTransaction();transaction.show(fragment);transaction.commit();// 或者状态丢失的提交transaction.commitAllowingStateLoss();
有时候会遇到Crash,大概意思是在状态保存后不能提交事务操作。
IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1493) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1511) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:638) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:617)
从异常的堆栈信息分析开始,调用FragmentTransaction的commit方法
FragmentTranstraction.commit() -> FragmentManager.enqueueAction() -> FragmentManager.checkStateLoss()
FragmentTranstraction的实现类 BackStackRecord的具体方法实现
public int commit() {return commitInternal(false);}public int commitAllowingStateLoss() {return commitInternal(true);}int commitInternal(boolean allowStateLoss) {if (mCommitted) throw new IllegalStateException("commit already called");if (FragmentManagerImpl.DEBUG) {Log.v(TAG, "Commit: " + this);LogWriter logw = new LogWriter(TAG);PrintWriter pw = new PrintWriter(logw);dump(" ", null, pw, null);}mCommitted = true;if (mAddToBackStack) {mIndex = mManager.allocBackStackIndex(this);} else {mIndex = -1;}mManager.enqueueAction(this, allowStateLoss);return mIndex;}
FragmentManager的实现类FragmentManagerImpl
public void enqueueAction(Runnable action, boolean allowStateLoss) {if (!allowStateLoss) {checkStateLoss();}synchronized (this) {if (mDestroyed || mHost == null) {throw new IllegalStateException("Activity has been destroyed");}if (mPendingActions == null) {mPendingActions = new ArrayList<Runnable>();}mPendingActions.add(action);if (mPendingActions.size() == 1) {mHost.getHandler().removeCallbacks(mExecCommit);mHost.getHandler().post(mExecCommit);}}}private void checkStateLoss() {if (mStateSaved) {throw new IllegalStateException("Can not perform this action after onSaveInstanceState");}if (mNoTransactionsBecause != null) {throw new IllegalStateException("Can not perform this action inside of " + mNoTransactionsBecause);}}
所以关键的是找到mStateSaved这个标记的变化的代码,
FragmentManager的实现类FragmentManagerImpl的saveAllState中对其标记为true
Parcelable saveAllState() {// Make sure all pending operations have now been executed to get// our state update-to-date.execPendingActions();// android.os.Build.VERSION.SDK_INT >= 11;if (HONEYCOMB) {// As of Honeycomb, we save state after pausing. Prior to that// it is before pausing. With fragments this is an issue, since// there are many things you may do after pausing but before// stopping that change the fragment state. For those older// devices, we will not at this point say that we have saved// the state, so we will allow them to continue doing fragment// transactions. This retains the same semantics as Honeycomb,// though you do have the risk of losing the very most recent state// if the process is killed... we'll live with that.mStateSaved = true;}//....}
saveAllState方法在FragmentActivity 的onSaveInstanceState被调用
/*** Save all appropriate fragment state.*/@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);Parcelable p = mFragments.saveAllState();if (p != null) {outState.putParcelable(FRAGMENTS_TAG, p);}}
FragmentController的saveAllState方法
public Parcelable saveAllState() {return mHost.mFragmentManager.saveAllState();}
最后再调用到FragmentManager的saveAllState
为了状态的正常保存和恢复,在Activity的状态保存后不能再提交事务了,
要么选择使用commitAllowingStateLoss来避免崩溃,或者在commit之前先调用FragmentManager.noteStateNotSaved来把状态改为false
public void noteStateNotSaved() {mStateSaved = false;}