1、参考资料
关于FragmentTransaction无法Commit两次的原因寻求
2、错误代码
val beginTransaction = requireActivity().supportFragmentManager.beginTransaction()
requireActivity().supportFragmentManager.fragments.forEach {
if (it::class == FragmentSearchResultMusic::class ||
it::class == FragmentSearchResultAlbum::class ||
it::class == FragmentSearchResultSinger::class
) {
beginTransaction.remove(it)
beginTransaction.commitAllowingStateLoss() // 注意!!!
}
}
- 抛出的异常信息是:
commit already called
3、源码分析
- 源码版本:androidx.fragment:fragment-ktx:1.2.5
- 先看
FragmentTransaction
对象,是通过beginTransaction()
方法获取的,深入看其源码实现:
# FragmentManager
@NonNull
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
- 该方法返回的是一个
BackStackRecord
实例对象,继承了FragmentTransaction
抽象类,commit
方法的具体实现就在该类中 - 找到
commit
方法
#BackStackRecord
@Override
public int commit() {
return commitInternal(false);
}
- 最终调用的是
commitInternal
方法
#BackStackRecord
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;
}
mCommitted
变量值,初始为 false,调用一次commitInternal
,置为 true,此时再调用commitInternal
,会抛出commit already called
异常。故我们使用FragmentTransaction
时,每次beginTransaction
得到的对象只能进行一次commit
操作。要进行第二次commit
只能再次通过beginTransaction
得到新的FragmentTransaction
对象。