深夜记一个大坑:illegalStateException:can not perform this action after onSaveInstanceState

来源:互联网 发布:医疗卫生软件竞争格局 编辑:程序博客网 时间:2024/05/03 18:29

好吧,其实重点不在于这个Excpetion…

项目采用了MVP模式,有1个Activity,3个Fragment,通过Presenter来切换Fragment,其中,Presenter中创建并保存了这3个Fragment的实例(避免不断的重复创建新的实例)

我在用AlarmManager设置了一个闹铃提醒(其context 是MainActivity),
这个提醒会启动一个BroadcastReceiver,在这个BroadcastReceiver中,我需要去更新UI,,,
本来嘛,一开始,出于条件反射,就想使用Handler,然后,由于太懒(应该还是条件反射哈哈),用Handler实在是太麻烦了。
于是,我灵机一动(坑了自己一把),就想把Presenter写成单例这里写图片描述
然后就可以在BroadcastReceiver中调用到Presenter了,然后就可以轻易的更新UI!!
这里写图片描述
然后,然后,,
一切执行得很顺利,一直到我手贱打开app,退出app,又打开app,,,咦,怎么变空白了???
一时间感觉摸不着头脑,然后我试着切换到另一个Fragment,,,没错,出现了标题中的那个异常,W……T……F……这什么鬼,明明是在onCreate中执行commit的啊,,,好吧,然而明明并帮不了我
然后便上google到stackoverflow等站遨游一番。。
以下便是采集到的战果:

  • 在onResume中执行commit(3.0以前)
  • 在onPostResume中执行commit(3.0及以后)
  • 在onResumeFragments中执行commit
  • 重写onSaveInstanceState,让其实现为空
  • 还有著名的”用commitAllowStateLoss来替代commit“
  • 重写Activity的onBackPress方法

这么多方法,前后查找包括测试就花了2个多小时(包括很多无果的查找和测试)。。。。然并卵
于是,我继续到处搜查,
直到,,我看到了一篇文章说明的情况和我非常的相似:使用AlarmManager设置闹钟,AlarmActivity接收提醒并做UI更新(他是创建DialogFragment)……
好吧,看完一堆说明之后,我发现跟他还是 不!一!样!
不一样在什么地方呢,不一样在他是使用了上面提到的方法解决的。。

然后我就开始受不了,这这这世界是怎么了,怎么连google都解决不了了。。

然后,我想起了一句话:最难跳出的坑总是你自己设下的。。(好吧,这是我说的)

于是我不再google,开始自己一点一点的调试,在某个瞬间,突然觉得自己像傻逼一样:既然页面空白,那应该首先考虑到是不是Fragment没有初始化呢……(这个时候,我开始意识到真正的错误不是那个异常,而是有幕后黑手,而这个黑手就是我自己培养出来的。。)

然后,我测试了几个Fragment的onCreate方法和onDestroy方法,我打开app,关闭app,打开app,,果然不出我所料!这些方法都只执行了一遍!!

然后就想到一件原先意想不到的事情,Activity销毁后,Presenter单例并没有被销毁!!一测试果不其然。

到这里,就知道为什么报那个异常了吧:Fragment已经被销毁(执行了onDestroy方法,是 “After onSaveInstanceState”的),然后我重新打开app,并没有创建新的Fragment,就执行了commit

至于静态的Presenter为什么不会被销毁呢,好吧,我确实不知道,怪我孤陋寡闻。

然后随便一查,单例所造成的内存泄漏
看到这篇文章 说到静态变量销毁的2种情况:
1. 进程死了
2. 所在上下文从ClassLoader里面卸载了

至此,明白了此次bug造成的原因,,果然还是自己造的坑容易进难出。。。。

最后,我当然还是要使用单例的,毕竟对handler实在是反感,怎么办呢,现在就好办了,在Activity的onDestroy方法中释放Presenter即可。

1 0
原创粉丝点击