您的位置:首页 > 移动开发 > Android开发

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()

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,就会丢失状态,然后挂机,否者就会出现我刚刚的狗血问题。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐