四、重新创建activity
有几个场景中,activity是由于正常的程序行为而被Destroy的,例如当用户点击返回按钮或是activity通过调用finish()来发出停止信号。系统也有可能会在activity处于stop状态且长时间不被使用,或是在前台activity需要更多系统资源时关闭后台进程,以图获取更多的内存。
当activity是因为用户点击Back按钮或是activity通过调用finish()结束自己时,系统就会丢失了对activity实例的引用,因为这一行为意味着不再需要这个activity了,然而,如果因为系统资源紧张而导致activity的Destroy,系统会在用户回到这个activity时有这个activity存在过的记录,系统会使用那些保存的记录数据(描述了当activity被Destroy时的状态)来重新创建一个新的activity实例,那些被系统用来恢复之前状态而保存的数据叫做“instance state”, 它是一些存放在Bundle对象中的key-values pairs(请注意这里的描述,这对理解onSaveInstanceState执行时刻很重要)
Caution:你的activity会在每次旋转屏幕时被destroyed与recreated。当屏幕改变方向时,系统会Destroy与Recreate前的activity,因为屏幕配置的改变,你的activity可能需要加载另一些替代的资源(例如layout)
默认情况下,系统使用Bundle实例来保存每一个View(视图)对象中的信息(例如输入EditText中的文本内容)
因此,如果activity被destroyed与recreated,则layout的状态信息会自动回复到之前的状态。然而,activity也许存在更多你想要恢复的状态信息,例如,记录用户Progress的成员变量(member variables)
Note: 为了使Android系统能够恢复activity中的View状态,每个View都必须有一个唯一ID。由android:id定义
为了可以保存额外更多的数据到saved instance state。在activity的生命周期里面存在一个额外的回调函数,你必须重写这个函数。该回调函数并没有在前面课程的图片示例中显示,这个方法是onSaveInstanceState(),当用户离开activity时,系统会调用它。当系统调用这个函数时,系统会在activity被异常Destroy时传递Bundle对象,这样我们就可以增加额外的信息到Bundle中并保存到系统中,若系统在activity被Destroy之后,onRestoreInstanceState()方法与onCreate()方法中
Figure2. 当系统开始停止activity时,只有在activity实例会需要重新创建的情况下才会调用到onSaveInstanceState(1)。在这个方法里面可以指定额外的状态数据到Bundle中如果这个activity被destroyed然后这个实例又需要被重新创建时,系统会传递在(1)中的状态数据到onCreate(2)与onRestroreInstanceState(3)
( 通常来说,跳转到其它的activity或点击Home都会导致当前的activity执行onSaveInstanceState,因为这种情况下的activity都是有可能会被destroy并且是需要保存状态以便后续恢复使用 ,而从跳转的activity点击back回到前一个activity,那么跳转的activity是执行退栈的操作,所以这种情况下是不会执行onSaveInstanceState的,因为这个activity不可能存在需要重建的操作)
2.保存activity状态
当我们的activity开始stop,系统会调用onSaveInstanceState(), activity可以用键值对的集合来保存状态信息。这个方法会默认保存activity视图的状态信息,如在EditText组件中的文本或ListView的滑动位置。
为了给activity保存额外的状态信息,你必须实现onSaveInstanceState()并增加key-value pairs到Bundle对象中,例如:
staticfinal String STATE_SCORE = "playerScore";
staticfinal String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState){
// Save the user current state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Cauthion:必须要调用onSaveInstanceState()方法的父类实现,这样默认的父类实现才能保存视图状态的信息。
3.恢复activity状态
当activity从Destroy中重建,我们可以从系统传递的activity的Bundle中恢复保存的状态。onCreate()与onRestoreInstanceState()回调方法都接收到了同样的Bundle,里面包含了同样的实例状态信息。
由于onCreate()方法会在第一次创建新的activity实例与重新创建之前被Destroy的实例时被调用,我们必须在尝试读取Bundle对象前检测它是否为null。如果它为null,系统则是创建一个新的activity实例,而不是恢复之前被Destroy的activity。
下面是一个示例:演示在onCreate方法里面恢复一些数据:
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
我们也可以选择实现onRestoreInstanceState(),而不是在onCreate方法里面恢复数据。onRestoreInstanceState()方法会在onStart()方法之后执行,系统仅仅会在存在需要恢复的状态信息时才会调用onRestoreInstanceState(),因此不需要检查Bundle是否为null.
public void onRestoreInstanceState(Bundle savedInstanceState){
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
Caution:与上面保存一样,总是需要调用onRestoreInstanceState()方法的父类实现,这样默认的父类实现才能保存视图状态的信息。更多关于运行时状态改变引起的recreate我们的activity。请参考 Handling Runtime Changes