onSaveInstanceState(Bundle outState)

在设备运行中发生配置变更时,如设备旋转,需采用某种方式保存以前的数据。覆盖以下Activity方法就是一种实现方式:

protected void onSaveInstanceState(Bundle outState)

该方法通常在onPause()onStop()以及onDestroy()方法之前由系统调用。

方法onSaveInstanceState(...)默认的实现要求所有activity的视图将自身状态数据保存在Bundle对象中。Bundle是存储字符串键与限定类型值之间映射关系(键-值对)的一种结构。

之前已使用过Bundle,如下列代码所示,它作为参数传入onCreate(Bundle)方法:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...

覆盖onCreate(...)方法时,我们实际是在调用activity超类的onCreate(...)方法,并传入收到的bundle。在超类代码实现里,通过取出保存的视图状态数据,activity的视图层级结构得以重新创建。

覆盖onSaveInstanceState(Bundle)方法

可通过覆盖 onSaveInstanceState(...) 方法,将一些数据保存在 Bundle 中,然后在onCreate(...)方法中取回这些数据。设备旋转时,将采用这种方式保存mCurrentIndex变量值。

首先,打开QuizActivity.java文件,新增一个常量作为将要存储在bundle中的键-值对的键,如代码清单3-5所示。

代码清单3-5 新增键?值对的键(QuizActivity.java)

public class QuizActivity extends Activity {

    private static final String TAG = "QuizActivity";
    private static final String KEY_INDEX = "index";

    Button mTrueButton;
    ...

然后,覆盖onSaveInstanceState(...)方法,以刚才新增的常量值作为键,将mCurrentIndex变量值保存到Bundle中,如代码清单3-6所示。

代码清单3-6 覆盖onSaveInstanceState(...)方法(QuizActivity.java)

    mNextButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCurrentIndex = (mCurrentIndex + 1) % mAnswerKey.length;
            updateQuestion();
        }
    });

    updateQuestion();
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    Log.i(TAG, "onSaveInstanceState");
    savedInstanceState.putInt(KEY_INDEX, mCurrentIndex);
}

最后,在onCreate(...)方法中查看是否获取了该数值。如确认获取成功,则将它赋值给变量mCurrentIndex,如代码清单3-7所示。

代码清单3-7 在onCreate(...)方法中检查存储的bundle信息(QuizActivity.java)

    ...

    if (savedInstanceState != null) {
        mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0);
    }

    updateQuestion();
}

运行GeoQuiz应用。单击下一步按钮。现在,无论设备自动或手动旋转多少次,新创建的QuizActivity都将会记住当前正在回答的题目。

注意,我们在Bundle中存储和恢复的数据类型只能是基本数据类型(primitive type)以及可以实现Serializable接口的对象。创建自己的定制类时,如需在onSaveInstanceState(...)方法中保存类对象,记得实现Serializable接口。

测试onSaveInstanceState(...)的实现是个好习惯,尤其在需要存储和恢复对象时。设备旋转很容易测试,但测试低内存状态就困难多了。比如Android为回收内存而销毁activity的场景。


覆盖onSaveInstanceState(...)方法并不仅仅用于处理设备旋转相关的问题。用户离开当前acitivity管理的用户界面,或Android需要回收内存时,activity也会被销毁。

不过Android从不会为了回收内存,而去销毁正在运行的activity。activity只有在暂停或停止状态下才可能会被销毁。此时,会调用onSaveInstanceState(...)方法。

调用onSaveInstanceState(...)方法时,用户数据随即被保存在Bundle对象中。然后操作系统将Bundle对象放入activity记录中。

为便于理解activity记录,我们增加一个暂存状态(stashed state)到activity生命周期,如图3-14。

onSaveInstanceState(Bundle outState)_第1张图片

图3-14 完整的activity生命周期

activity暂存后,Activity对象不再存在,但操作系统会将activity记录对象保存起来。这样,在需要恢复activity时,操作系统可以使用暂存的activity记录重新激活activity。

注意,activity进入暂存状态并不一定需要调用onDestroy()方法。不过,onPause()onSaveInstanceState(...)通常是我们需要调用的两个方法。常见的做法是,覆盖onSaveInstanceState(...)方法,将数据暂存到Bundle对象中,覆盖onPause()方法处理其他需要处理的事情。

有时,Android不仅会销毁activity,还会彻底停止当前应用的进程。不过,只有在用户离开当前应用时才会发生这种情况。即使这种情况真的发生了,暂存的activity记录依然被系统保留着,以便于用户返回应用时activity的快速恢复。

那么暂存的activity记录到底可以保留多久?前面说过,用户按了后退键后,系统会彻底销毁当前的activity。此时,暂存的activity记录同时被清除。此外,系统重启或长时间不使用activity时,暂存的activity记录通常也会被清除。


你可能感兴趣的:(onSaveInstanceState(Bundle outState))