commit和commitAllowingStateLoss方法的区别
遇到的问题
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2044) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2067) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:680) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:634)
前两天使用EventBus在别的页面对MainAcitvity里的Fragment进行操作时,爆出来这个异常,网上找到的处理方案是把 FragmentTransaction 调用的commit()方法替换为 commitAllowingStateLoss()方法即可以处理了,至于为什么用这个方法,最近研究了一下源码,在这里分享一下。
源码分析及验证
public abstract class FragmentTransaction { …… public abstract int commit(); public abstract int commitAllowingStateLoss();}
首先查看FragmentTransaction,很简单的一个笼统类,不多说,下面寻觅真正的实现类
在这里插入图片形容
通过上图的方式,右键类名点击 Find Usages,而后在Find视图窗口里找到继承自FragmentTransaction的实现类:BackStackRecord,下面来看一下这个类:
final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, Runnable { …… public int commit() { return commitInternal(false); } public int commitAllowingStateLoss() { return commitInternal(true); } int commitInternal(boolean allowStateLoss) { …… mManager.enqueueAction(this, allowStateLoss); …… } ……}
省略掉无关逻辑,commit()和commitAllowingStateLoss()两个方法都调用了同一个方法commitInternal(),commitInternal()方法接收一个boolean的参数allowStateLoss(允许状态丢失),commitInternal()方法里调用了FragmentManager的enqueueAction()方法,并且把boolean参数传递了进去,而后继续看FragmentManager:
public abstract class FragmentManager { …… boolean mStateSaved; …… public void enqueueAction(Runnable action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } } private void checkStateLoss() { if (mStateSaved) { throw new IllegalStateException( "Can not perform this action after onSaveInstanceState"); } } …… Parcelable saveAllState() { …… if (HONEYCOMB) { mStateSaved = true; } …… } …… public void noteStateNotSaved() { mStateSaved = false; } public void dispatchCreate() { mStateSaved = false; …… } public void dispatchActivityCreated() { mStateSaved = false; …… } public void dispatchStart() { mStateSaved = false; …… } public void dispatchResume() { mStateSaved = false; …… } …… public void dispatchStop() { mStateSaved = true; …… } ……}
这里可以看出来,enqueueAction()根据allowStateLoss参数做了一个判断,假如allowStateLoss=false,也就是假如你调用的是commit()方法的话,那么就要做一个判断,假如mStateSaved为true,那么就要抛出异常,这个异常就是文章开头所说的那个异常。
问题的关键来了,这个mStateSaved是如何变化的:
上面的代码可以看出在saveAllState()方法和dispatchStop() 方法中,mStateSaved会变为true(HONEYCOMB意思是能否大于api11,不用管),这两个方法分别是在FragmentActivity的onSaveInstanceState()和onStop()中被调用,而onSaveInstanceState()的调用时机是在onPause()之后onStop()之前,这样可以总结出来当Activity的onSaveInstanceState()方法调用之后假如调用了该Activity的FragmentTransaction的commit方法,就会抛出异常(验证文章开头的结论)。
相反的,其余几个将mStateSaved变为false的方法,根据方法名可以推断出是在FragmentActivity的生命周期的其余几个回调方法里运行的,可以推断出,当Activity重新回到栈顶显示之后,调用commit是没有问题的。
总结
当Activity中的Fragment发生了变化,FragmentManager会在特定的时间点保存所有Fragment的状态,方便Activity由于被回收之后重建时,重新设置Fragment,假如状态没有被保存,那么Activity就只能按照默认方式显示每个Fragment,显示效果可能跟app的预期不一样。
假如项目中有特定的需求,比方需要在别的Activity中通过广播或者者Eventbus的方式控制MainActivity的Fragment切换,那么就需要使用commitAllowingStateLoss()方法来避免异常。
大家需要按照自己的需求来选择合适的方法使用。
假如文章中有错误或者者不严谨的地方,希望提出来,共同学习。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » commit和commitAllowingStateLoss方法的区别