Android - java.lang.IllegalState

2019-04-08  本文已影响0人  九号锅炉

以下堆栈信息日志是常见的illegalStateExecption日志。笔者是当应用出于后台时,网络响应更新fragment时出现以下问题。本文将对该异常抛出的的时间和原因进行解释,并对如何避免异常的发生提出一些意见。

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

异常出现的原因

根据日志消息,顾名思义,该异常发生的原因是在Activity的state已经被保存之后仍然试图调用commit去提交FragmentTransaction. 在详细解析这句话真正意思之前,让我们首先了解一下究竟onSaveInstance里做了什么。安卓系统随时可能杀死进程来释放内存,后台Activity可能随时被杀死。因此Framework通过调用onSaveInstanceState( ) 来保存activity的状态State. FrameWork通过Bundle对象来保存state, 其中记录下dialog,fragment,view等视图结构和状态。这样即便Activity因为异常情况被系统杀死,还是可以通过保存下了的状态来恢复原来的视图。

了解了onSaveInstance具体做了什么之后,再来讨论为什么onSaveInstance被调用之后不能调用commit.原因就是,onSaveInstance已经用Bundle对象将Activity所有状态视图信息保存下来了,这时候想要把这个事务提交上去是不可能的,安卓开发团队出于保护用户界面不被影响,不惜一切代价防止保存的状态不丢失,因此采用抛出异常的方式来解决。听起来有点抽象,其实可以通过一个例子来理解,全班同学的卷子都已经上交并且批改结束,分数排名都出来了。这时候你再提交卷子肯定是不行的,谁知道你有没有偷抄,如果你偷抄的话岂不是影响了班级的排名。

什么时候会抛出异常

如果你之前已经遇到过这样的异常,可能已经注意到在不同的安卓版本上异常抛出的可能性不一样。例如,老的版本抛出异常的概率更小;或者如果应用程序使用support library时抛出异常的概率更大。这会让人觉得是不是support library 有问题。然而事实上不是如此。

抛出异常的概率不同主要原因是Android3.0(HoneyComb)其之后版本中Activity生命周期的显著差异造成的。在3.0以前,onSaveInstance是在onPause调用之前调用,而3.0以后onSaveInstance是在onStop调用之前调用的,这样的话3.0以前在onSaveInstance之后调用commit的概率更高了,因此异常发生的概率也就更高了。

如何避免异常发生

当理解了异常发生背后的真相之后,如何避免就轻而易举了。

上一篇下一篇

猜你喜欢

热点阅读