内存重启及相关并发事件

由内存重启引发的相关事件

Posted by Cedar7 on December 26, 2017

内存重启及相关并发事件

何为内存重启?安卓app有一种特殊情况,就是 app运行在后台的时候,系统资源紧张的时候导致把app的资源全部回收(杀死app的进程),这时把app再从后台返回到前台时,app会重启。这种情况下文简称为:“内存重启”。(屏幕旋转等配置变化也会造成当前Activity重启,本质与“内存重启”类似。
此种现象的发生会引起很多关于系统状态的问题,Activity与Fragment的相关绑定事件引起的相关问题,内存重启之前状态的保存和重启之后状态的回复问题,这些问题我会在之后给出解决方案。但是我要先讲一下关于这方面最重要的两个方法。

onSaveInstanceState()和onRestoreInstanceState()

1. 作用与用法

其最根本的作用其实就是,当内存不足对Activity进行回收时,保存一些有用的信息;在再次打开该Activity时将数据恢复。它们并不是生命周期方法,它们不同于onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由==系统==销毁一个Activity时,onSaveInstanceState() 会被调用。但是当==用户主动==去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

2. onSaveInstanceState() 什么时候调用

很多人都引用下面这句话:👇👇👇
Android calls onSaveInstanceState() before the activitybecomes vulnerable to being destroyed by the system, but does not bothercalling it when the instance is actually being destroyed by a user action (suchas pressing the BACK key).
其实我对这句话的理解就是:当==系统==作为这个事件的主观发起者时,就会被调用;当==用户==为这个事件的主观发起者时,是不会被调用的。而且我们在日常开发中遇到的问题大多都是由系统发起调用的,所以我们只需记住系统调用的的几种情况即可:

(1)、当用户按下HOME键的时候。
这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,因此系统会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。

(2)、长按HOME键,选择运行其他的程序时。

(3)、按下电源按键(关闭屏幕显示)时。

(4)、从activity A中启动一个新的activity时。

(5)、屏幕方向切换时,例如从竖屏切换到横屏时。
在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState()一定会被执行,且也一定会执行onRestoreInstanceState()。
(6)、当程序运行过程中,有电话打进来。

总而言之,onSaveInstanceState()的调用遵循一个重要原则,即当系统存在“==未经你许可==”(非主观意愿)时销毁了我们的activity的可能时,则onSaveInstanceState()会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。如果调用,调用将发生在onPause()或onStop()方法之前。(虽然测试时发现多数在onPause()前)。

3. onRestoreInstanceState()什么时候调用

只有当activityA“确实”是被==系统==销毁了,当再次回到A时,onRestoreInstanceState()就会被调用。如果A退出之后马上再回来,这时其实A并没有被回收,所以onRestoreInstanceState()不会被调用,它与onSaveInstanceState()一般不是成对出现的,onSaveInstanceState()出现的场景更多一些。onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之间调用。

4.注意事项

(1) 对于系统的一些控件而言,当发生内存重启的情况时,由于几乎所有的UI控件都实现了onSaveInstanceState()方法,所以当这些控件被再次启动的时候会自动恢复。做到这一点的唯一要求就是:给这个UI控件指定一个唯一ID(android:id),剩下的事情就可以交给系统处理了。
(2)这两个方法只适合保存瞬态数据, 比如UI控件的状态,成员变量的值等,而不应该用来保存持久化数据,持久化数据应该当用户离开当前的 activity时,在onPause()中保存(比如将数据保存到数据库或文件中)。说到这里,还要说一点的就是在onPause()中不适合用来保存比较费时的数据,所以这点要理解。由于onSaveInstanceState()方法方法不一定会被调用,因此不适合在该方法中保存持久化数据,例如向数据库中插入记录等.保存持久化数据的操作应该放在onPause()中。若是永久性值,则在onPause()中保存;若大量,则另开线程吧,别阻塞UI线程。