FragmentTransaction ft = fragmentManager.beginTransaction();
ft.commit();
ft.commitAllowingStateLoss();
ft.commitNow();
ft.commitNowAllowingStateLoss();
FragmentTransaction提交事务提供了上述四种方法,我们该怎么用呢?
commit() vs commitAllowingStateLoss()
commit()和commitAllowingStateLoss()在实现上唯一的不同就是当你调用commit()的时候, FragmentManger会检查mDestory, mHost 如果mHost ==null, 就抛出IllegalStateException.
看源码知道mHost 是在FragmentActivity的onDestroy 中被置空的(注释5,6,7),也就是说FragmentActivity onDestroy 之后再commit的话,就会抛出异常(注释2,3),commitAllowingStateLoss() 提交则是直接return(注释4),
那为什么commitAllowingStateLoss可能会丢失fragmentManager状态呢?
即save之后任何被添加或被移除的Fragments,
源码可知,fragmentManager的状态是在onsaveInstance中保存的,ondestory的时候已经保存了,所以之后提交的不会被保存
BackStackRecord.java
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", pw);
pw.close();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex();
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
FragmentManager.java
void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
if (mHost == null) {//2
if (mDestroyed) {//3
throw new IllegalStateException("FragmentManager has been destroyed");
} else {
throw new IllegalStateException("FragmentManager has not been attached to a "
+ "host.");
}
}
checkStateLoss();
}
synchronized (mPendingActions) {
if (mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;//注释4
}
throw new IllegalStateException("Activity has been destroyed");
}
mPendingActions.add(action);
scheduleCommit();
}
}
void dispatchDestroy() {
mDestroyed = true;//5
execPendingActions(true);
endAnimatingAwayFragments();
dispatchStateChange(Fragment.INITIALIZING);
mHost = null;//6
mContainer = null;
mParent = null;
...
}
FragmentActivity.java
protected void onDestroy() {
super.onDestroy();
mFragments.dispatchDestroy();//7
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
markFragmentsCreated();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);//8
}
commit() VS commitNow()
commit 可以将action加入回退栈, 将action加入到队列中,用handler异步执行
commitNow 不可以加入回退栈, 立即执行
-
如果你需要同步的操作, 并且你不需要加到back stack里, 使用
commitNow().
support library在FragmentPagerAdapter里就使用了commitNow()来保证在更新结束的时候, 正确的页面被加上或移除. -
如果你操作很多transactions, 并且不需要同步, 或者你需要把transactions加在back stack里, 那就使用
commit(). -
如果你希望在某一个指定的点, 确保所有的transactions都被执行, 那么使用
executePendingTransactions().BackStackRecord.java
@Override public void commitNow() { disallowAddToBackStack(); mManager.execSingleAction(this, false); }