Android从API21(5.0)开始,增加了 onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) 方法,多了个PersistableBundle参数,作用在于当Activity从意外结束恢复时,传递结束前保存的Activity历史数据,从而恢复现场。
怎么使用呢?
- 1.Manifest里面的<activity>标签增加 android:persistableMode="persistAcrossReboots"
persistableMode有三个值:
persistNever:从不,顾名思义,就是不起作用,不调用那两个方法持久化页面的数据或者状态。(原文:If this activity forms the root of a task then that task will not be persisted across reboots)
persistRootOnly:默认值。仅仅会作用在根activity或者task中。(原文:The default. If this activity >forms the root of a task then that task will be persisted across reboots but only the launching intent >will be used. If the task relinquishes its identity then the intent used is that of the topmost inherited >identity. All activities above this activity in the task will not be persisted. In addition this activity will >not be passed a PersistableBundle into which it could have stored its state.)(有点难理解哈,看不>懂这个说的是啥,各位看官自己来)
persistAcrossReboots:重启设备,会持久化页面的数据或者状态,同理,如果位于这个页面之上的页面也设置了这个值,上面的页面也会被持久化。最后系统会将你保存的数据,在重启后打开这个页面>的时候,会调用oncreate()具有两个参数的方法。你只要在第二个参数PersistableBundle 中取出你保>存的数据就OK了。
查看这段说明的来源文章--Android之activity的数据持久化(persistableMode详解)
- 2.重写三个方法
- onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?)
可以看下源码的注释看一下关于PersistableBundle的解释,大意是这个对象保存了最近一次在onSaveInstanceState方法中存入的数据,那么理论上,只要我重写了onSaveInstanceState,并且将一些临时数据存进去,那么如果遇到Activity意外关闭或者设备断电(关机),重新进入这个Activity的时候,这些数据将在PersistableBundle中得以恢复。
- onRestoreInstanceState(savedInstanceState: Bundle?, persistentState: PersistableBundle?)
同样看下注释大意是这个方法用于Activity重新初始化的时候,恢复在onSaveInstanceState保存的数据,通常的实现,是在onCreate里面恢复数据,但是有时候需要在所有的初始化流程结束之后再恢复数据,那么就可以在这个方法里面进行
- onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?)
看注释注释真™长,大意是Activity在临死之前会调用一下这个方法,Activity重生之后呢,会把你保存的数据传给上面提到的两个方法;不要将这个方法跟Activity的生命周期方法混为一谈,像类似onPause这种,是每次离开Activity都会调用的,这个方法就不一定了;后面一段看不太懂,大概是会为每个视图分配一个ID?默认会保存每个视图的状态,也可以自己实现;最后是该方法会在onStop前执行,不定在onPause前后
具体怎么弄?--直接上代码
//定义变量a当作需要恢复的数据
var a: Double = 1.0
//获取变量a的KEY
val KEY_A = "a"
//获取Bundle的KEY
val KEY_B = "b"
onCreate()
//只有API>=21会调用这个,<21会调用onCreate(savedInstanceState: Bundle?)
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
Log.d("onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?)")
if (persistentState == null) {
Log.d("persistentState is null")
} else {
Log.d("persistentState is not null")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
persistentState?.let {
var bundle = persistentState.getPersistableBundle(KEY_B)
bundle?.let {
a = bundle.getDouble(KEY_A)
Log.d("a savedInstanceState history==" + a)
}
}
}
if (a == 1.0) {
a = Math.random()
Log.d("a init == " + a)
}
Log.d("==========================================================================\r\n")
}
onSaveInstanceState
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
Log.d("onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?)")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
outPersistentState?.let {
Log.d("save a in outPersistentState == " + a)
var bundle = PersistableBundle()
bundle.putDouble(KEY_A, a)
outPersistentState.putPersistableBundle(KEY_B, bundle)
}
}
Log.d("==========================================================================\r\n")
}
onRestoreInstanceState
override fun onRestoreInstanceState(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onRestoreInstanceState(savedInstanceState, persistentState)
Log.d("onRestoreInstanceState(savedInstanceState: Bundle?, persistentState: PersistableBundle?)")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
persistentState?.let {
var bundle = persistentState.getPersistableBundle(KEY_B)
bundle?.let {
a = bundle.getDouble(KEY_A)
Log.d("a persistentState history" + a)
}
}
}
Log.d("==========================================================================\r\n")
}
看下运行结果:
可以发现,只有在屏幕旋转时,参数才得以恢复,其他情况下都是丢失数据,重新开始初始化。为此,看了挺多别人的博客,居然没人提及这样的问题,颇感疑惑,原本我以为可能需要进行类似SharedPreferences的commit之类的操作,但是也没发现有类似的方法。
曲线救国的方法
在onSaveInstanceState用SharedPreference保存数据,像这样:
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
super.onSaveInstanceState(outState, outPersistentState)
Log.d("onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?)")
var sp = getSharedPreferences(KEY_SP, Context.MODE_PRIVATE)
sp.edit().putFloat(KEY_A, a.toFloat()).commit()
Log.d("==========================================================================\r\n")
}
要恢复直接拿回来就好
//只有API>=21会调用这个,<21会调用onCreate(savedInstanceState: Bundle?)
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
Log.d("onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?)")
var sp = getSharedPreferences(KEY_SP, Context.MODE_PRIVATE)
sp?.let {
a = sp.getFloat(KEY_A, 1F).toDouble()
Log.d("a history from sp==" + a)
}
if (a == 1.0) {
a = Math.random()
Log.d("a init == " + a)
}
Log.d("==========================================================================\r\n")
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onRestoreInstanceState(savedInstanceState, persistentState)
Log.d("onRestoreInstanceState(savedInstanceState: Bundle?, persistentState: PersistableBundle?)")
var sp = getSharedPreferences(KEY_SP, Context.MODE_PRIVATE)
sp?.let {
a = sp.getFloat(KEY_A, 1F).toDouble()
Log.d("a history from sp==" + a)
}
Log.d("==========================================================================\r\n")
}
看下运行结果:显然,这样就不会丢失数据了
总结
onSaveInstanceState在一定程度上为我们提供了为Activity保持现场的途径(顺道一提Fragment也支持重写onSaveInstanceState,但没有onRestoreInstanceState,直接将数据给到onCreate、onCreateView、onActivityCreated),但是不知道是Android自身BUG还是我的使用不到位(如果确实是使用不当,望有大神指点一二),默认的保存方式只能在很少的使用场景下生效,为此,只能使用替代的方式来保存数据(SharedPreferences),这种方式有好有坏。
- 优点
至少数据不会丢失,你得先保证这一点,才能说其他
绕开了API>=21的限制,因为不需要依赖PersistableBundle了 -
缺点
只能存少数几种元数据格式的数据,显然有很多时候我们需要存一个复杂的对象,这个只能另想办法
SharedPreferences有限的存储格式