commitNowAllowingStateLoss导致的FragmentManager is already executing transactions

fragment版本1.3.6

Fatal Exception: java.lang.IllegalStateException
FragmentManager is already executing transactions
androidx.fragment.app.FragmentManager.ensureExecReady (FragmentManager.java:4)
androidx.fragment.app.FragmentManager.execSingleAction (FragmentManager.java:11)
androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss (BackStackRecord.java:2)

查看源码发现发生这个异常是因为FragmentManager一次操作未结束时又进行了下一次操作。(通过mExecutingActions这个变量进行判定的)

说明有两次Fragment操作很接近,并且因为是commitNowAllowingStateLoss,代码是同步的且所有相关操作都在主线程,不存在多线程。所以一般应该是发生了嵌套行为。即:

mExecutingActions =true;
xxx();//xxx方法中又同步调用了Fragment的操作,导致发现mExecutingActions为true抛出异常
mExecutingActions =false;

查看异常上下文,发现是在“添加Fragment—》Fragment内部初始化相关组件失败—》回调到外部移除该Fragment“,且移除Fragment的方法使用的是runOnUiThread,runOnUiThread里面判定了如果是主线程,则直接运行Runnable,此时是同步代码,发生了上方的同步行为触发该异常。

主要思路为通过异步的方式避免这种嵌套调用就行了

使用commitAllowingStateLoss代替commitNowAllowingStateLoss,因为commitNowAllowingStateLoss是同步,commitAllowingStateLoss是异步。

使用handler.post或者view.post替代runOnUiThread,实现异步。

需求:滑动变化页面,tab栏随之变化(很一般的常见需求了) bug现象描述:(1)Fragment没有被创建和添加进viewPager,(2)有时候activity加载出来时crash,(3)有时候contain的Activity正常加载,试图滑动页面就crash Log信息: 11-23 18:50:53.667 15943-15943/? E/AndroidRuntime: FATA 这是因为FragmentManager会在状态保存后保存事务的回退栈,所以如果在状态保存后提交一个事务,那么这个事务就不会被保存在回退栈中。这可能会导致应用在恢复状态时出现不一致的状态。: 这个方法允许在状态已经被保存后提交事务,即使这可能会导致状态丢失。它不会抛出状态丢失的异常,但如果在状态保存后提交事务,那么这个事务就不会被保存在回退栈中,可能会导致应用在恢复状态时出现不一致的状态。通常来说,你应该尽量避免在状态已经保存后提交事务,因为这可能会导致应用的用户界面状态与实际的应用状态不一致。 java.lang.IllegalStateException: FragmentManager is already executing transactions at androidx.fragment.app.FragmentManagerImpl.ensureExecReady(FragmentManagerImpl.java:14) at androidx.fragment.app.FragmentManagerImpl.execSingleAction(... 在Activity初始化FragmentTabHost的时候,传入了一个fragmentmanager,就是getFragmentManager拿到的,因为tabhost要交互的是第一层的fragment ,是直接和activity相交互的。而在Fragment1里嵌套的viewpager ,因为要交互的是嵌套的Fragment,所以需要拿到ChildFragmentManager才行。里面viewpager的setadapter的时候使用的是。在用viewpager+tablayout+ 关于FragmentTransaction的各种提交方法: commit(),commitAllowingStateLoss(),commitNow()和commitNowAllowingStateLoss(). 作者Bryan Herbst发了一个blog The many flavors of commit()讨论这几个方法的特点和用途. 下文是中文摘要. FragmentTransactio... java.lang.IllegalStateException: FragmentManager is already executing transactions at android.support.v4.app.FragmentManagerImpl.ensureExecReady(FragmentManager.java:2006) at android.support.v4.app.FragmentManagerImpl Android 基础:Fragment 各种 Commit 使用注意事项和异常解析 Fragment进阶-commit使用细节及源码分析 Fragment的FragmentTransaction 的commit()和commitAllowingStateLoss()以及commitNow()和commitNowAllowingStateLoss() commit(), commitNow()和co... .beginTransaction() .remove((Fragment) view) .commitNowAllowingStateLoss();编译异常,提示找不到符号commitNowAllowingStateLoss() FragmentTransaction transa