@act262
2017-05-24T14:19:32.000000Z
字数 3421
阅读 1539
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.
*/
@Override
protected 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;
}