android fragment事务的提交使用的时候出现的一些问题。。
2017-03-30 10:58
495 查看
最近测试哥哥发现了一个问题。先说一下重现步骤。。
1.先安装3.3.0的版本,然后打开运行
2.然后切换到后台,安装3.3.1的新版本,
3.安装完后点开原型,会卡住第一屏。。。
说明:
重启app后,又一切正常。。。也就是只有覆盖安装,首次打开才会出现,尼玛!!!这就加大了调试难度。。
--------最后纠结了脑筋,各种排查,考虑过缺少常量,缺少数据,子线程抛出异常,等等,最后无果,最后发现,会不会是切换页面有问题,然后去看了一个早上的fragment源代码。。最后发现既然是一个单词引起的,我想砸电脑,(虽然后面发现这句代码好像不是我改的),不过算了,既然发现了,那就记录下卡壳遇到的坑以及分析过程,解决办法。。
fragment有4提交方式
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()
说你在
这里有另一个文章很好地分析了这个问题:Fragment Transactions & Activity State Loss
FragmentManger会检查是否已经存储了它自己的状态, 如果已经存了, 就抛出
那么如果你调用的是
并且是在
你可能会丢失掉什么状态呢?
答案是你可能会丢掉FragmentManager的状态, 即save之后任何被添加或被移除的Fragments.
举例说明:
1.在Activity里显示一个FragmentA;
2.然后Activity被后台,
3.在某个事件触发下, 你用FragmentB replace FragmentA , 使用的是
这时候, 用户再返回应用, 可能会有两种情况发生:
1.如果系统杀死了你的activity, 你的activity将会重建, 使用了上述步骤2保存的状态, 所以A会显示, B不会显示;
2.如果系统没有杀死你的activity, 它会被提到前台, FragmentB就会显示出来, 到下次Activity stop的时候, 这个包含了B的状态就会被存下来.
(上述测试可以利用开发者选项中的”Don’t Keep Activities”选项).
那么你要选择哪一种呢? 这就取决于你提交的是什么, 还有你是否能接受丢失.
一旦调用, 这个commit并不是立即执行的, 它会被发送到主线程的任务队列当中去, 当主线程准备好执行它的时候执行.
发送到主线程任务队列中去. 也即说它们都是异步的.
但是有时候你希望你的操作是立即执行的, 之前的开发者会在
即变异步为同步.
support library从v24.0.0开始提供了
之前用
而
所以
但是你不能对要加在back stack中的transaction使用
即
为什么呢?
想想一下, 如果你有一个提交使用了
紧接着又有另一个提交使用了
两个都想加入back stack, 那back stack会变成什么样呢? 到底是哪个transaction在上, 哪个在下? 答案将是一种不确定的状态, 因为系统并没有提供任何保证来确保顺序, 所以系统决定干脆不支持这个操作.
前面提过
所以它同样也有一个同步的兄弟
所以实际应用的时候怎么选择呢?
如果你需要同步的操作, 并且你不需要加到back stack里, 使用
support library在FragmentPagerAdapter里就使用了commitNow()来保证在更新结束的时候, 正确的页面被加上或移除.
如果你操作很多transactions, 并且不需要同步, 或者你需要把transactions加在back stack里, 那就使用
如果你希望在某一个指定的点, 确保所有的transactions都被执行, 那么使用
---------后面发现我的代码调用的是
这个会丢掉FragmentManager的状态, 即save之后任何被添加或被移除的Fragments.,所以。在首页的fragment我们最好调用commit,或者调用
commitAllowingStateLoss的时候要确保activit已经加载并且状态恢复了,因为切换到后台程序并没有杀死,再次打开的时候,会进activity的恢复生命周期。这个时候如果直接调用,commitAllowingStateLoss,就会丢失状态,然后挂机,否者就会出现我刚刚的狗血问题。。
1.先安装3.3.0的版本,然后打开运行
2.然后切换到后台,安装3.3.1的新版本,
3.安装完后点开原型,会卡住第一屏。。。
说明:
重启app后,又一切正常。。。也就是只有覆盖安装,首次打开才会出现,尼玛!!!这就加大了调试难度。。
--------最后纠结了脑筋,各种排查,考虑过缺少常量,缺少数据,子线程抛出异常,等等,最后无果,最后发现,会不会是切换页面有问题,然后去看了一个早上的fragment源代码。。最后发现既然是一个单词引起的,我想砸电脑,(虽然后面发现这句代码好像不是我改的),不过算了,既然发现了,那就记录下卡壳遇到的坑以及分析过程,解决办法。。
fragment有4提交方式
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()
commit() vs commitAllowingStateLoss()
用commit()提交有时候会遇到
IllegalStateException,
说你在
onSaveInstanceState()之后提交,
这里有另一个文章很好地分析了这个问题:Fragment Transactions & Activity State Loss
commit()和
commitAllowingStateLoss()在实现上唯一的不同就是当你调用
commit()的时候,
FragmentManger会检查是否已经存储了它自己的状态, 如果已经存了, 就抛出
IllegalStateException.
那么如果你调用的是
commitAllowingStateLoss(),
并且是在
onSaveInstanceState()之后,
你可能会丢失掉什么状态呢?
答案是你可能会丢掉FragmentManager的状态, 即save之后任何被添加或被移除的Fragments.
举例说明:
1.在Activity里显示一个FragmentA;
2.然后Activity被后台,
onStop()和
onSaveInstanceState()被调用;
3.在某个事件触发下, 你用FragmentB replace FragmentA , 使用的是
commitAllowingStateLoss().
这时候, 用户再返回应用, 可能会有两种情况发生:
1.如果系统杀死了你的activity, 你的activity将会重建, 使用了上述步骤2保存的状态, 所以A会显示, B不会显示;
2.如果系统没有杀死你的activity, 它会被提到前台, FragmentB就会显示出来, 到下次Activity stop的时候, 这个包含了B的状态就会被存下来.
(上述测试可以利用开发者选项中的”Don’t Keep Activities”选项).
那么你要选择哪一种呢? 这就取决于你提交的是什么, 还有你是否能接受丢失.
commit(), commitNow() 和 executePendingTransactions()
使用commit()的时候,
一旦调用, 这个commit并不是立即执行的, 它会被发送到主线程的任务队列当中去, 当主线程准备好执行它的时候执行.
popBackStack()的工作也是这样,
发送到主线程任务队列中去. 也即说它们都是异步的.
但是有时候你希望你的操作是立即执行的, 之前的开发者会在
commit()调用之后加上
executePendingTransactions()来保证立即执行,
即变异步为同步.
support library从v24.0.0开始提供了
commitNow()方法,
之前用
executePendingTransactions()会将所有pending在队列中还有你新提交的transactions都执行了,
而
commitNow()将只会执行你当前要提交的transaction.
所以
commitNow()避免你会不小心执行了那些你可能并不想执行的transactions.
但是你不能对要加在back stack中的transaction使用
commitNow(),
即
addToBackStack()和
commitNow()不能同时使用.
为什么呢?
想想一下, 如果你有一个提交使用了
commit(),
紧接着又有另一个提交使用了
commitNow(),
两个都想加入back stack, 那back stack会变成什么样呢? 到底是哪个transaction在上, 哪个在下? 答案将是一种不确定的状态, 因为系统并没有提供任何保证来确保顺序, 所以系统决定干脆不支持这个操作.
前面提过
popBackStack()是异步的,
所以它同样也有一个同步的兄弟
popBackStackImmediate().
所以实际应用的时候怎么选择呢?
如果你需要同步的操作, 并且你不需要加到back stack里, 使用
commitNow().
support library在FragmentPagerAdapter里就使用了commitNow()来保证在更新结束的时候, 正确的页面被加上或移除.
如果你操作很多transactions, 并且不需要同步, 或者你需要把transactions加在back stack里, 那就使用
commit().
如果你希望在某一个指定的点, 确保所有的transactions都被执行, 那么使用
executePendingTransactions().
---------后面发现我的代码调用的是
commitAllowingStateLoss
这个会丢掉FragmentManager的状态, 即save之后任何被添加或被移除的Fragments.,所以。在首页的fragment我们最好调用commit,或者调用
commitAllowingStateLoss的时候要确保activit已经加载并且状态恢复了,因为切换到后台程序并没有杀死,再次打开的时候,会进activity的恢复生命周期。这个时候如果直接调用,commitAllowingStateLoss,就会丢失状态,然后挂机,否者就会出现我刚刚的狗血问题。。
相关文章推荐
- android开发中使用高德地图出现的一些问题
- 使用android兼容包android-support-v4.jar出现的一些问题
- android 使用fragment切换,出现fragment重叠的问题
- 使用android兼容包android-support-v4.jar出现的一些问题
- Android基础_学习Fragment时候出现的一些错误[博客园]
- 使用viewpager或者fragmentActivity等一些v4包下的类,当我们按F3时无法查看到源码,这个时候就需要我们关联该源码,该源码的关联与android源码的关联不一样。
- Android ViewPaper使用FragmentPagerAdapter出现的FragmentManagerImpl为空的问题
- Android应用中使用Fragment组件的一些问题及解决方案总结
- 在使用android studio过程中,使用gradle编译的时候总会出现一些问题,下面是几个常见问题的解决方法。
- Android使用高德地图的时候出现的若干问题...
- Android中使用Thread线程出现的问题
- 使用gdiplus.lib出现的一些问题解决办法(不断增加中。。。)
- Android使用NDK开发项目时的一些问题
- 使用oradim.exe删除数据库实例的时候出现的小问题
- TeeChart 光标工具出现的问题以及一些使用方法
- 解决使用nvelocity时候template文件里面包含中文输出结果时候出现乱码的问题
- Android重新安装以及出现的一些问题和解决方案
- android ListView在使用中碰得一些问题的解决办法
- 使用sevlet提交表单出现乱码问题
- android客户端通过Get方式提交参数给服务器,使用URL和HttpURLConnection实现,以及乱码问题解决