Android InstanceState

发布于 2024-03-26 10:41:03 字数 5321 浏览 15 评论 0

Android 开发中我们常用 Activity,对 Activity 的生命周期也是了如指掌,然而我们往往会忽略两个方法, onSaveInstanceState()onRestoreInstanceState() ,在开发过程中很少用到,但在有时候掌握其用法会帮我们起到比较好的效果。

基本作用

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

在 activity 被杀掉之前调用保存每个实例的状态,以保证该状态可以在 onCreate(Bundle) 或者 onRestoreInstanceState(Bundle) (传入的 Bundle 参数是由 onSaveInstanceState 封装好的) 中恢复。这个方法在一个 activity 被杀死前调用,当该 activity 在将来某个时刻回来时可以恢复其先前状态。

例如,如果 activity B 启用后位于 activity A 的前端,在某个时刻 activity A 因为系统回收资源的问题要被杀掉,A 通过 onSaveInstanceState 将有机会保存其用户界面状态,使得将来用户返回到 activity A 时能通过 onCreate(Bundle) 或者 onRestoreInstanceState(Bundle) 恢复界面的状态。

onSaveInstanceState() 什么时候调用

从这句话可以知道,当某个 activity 变得"容易"被系统销毁时,该 activity 的 onSaveInstanceState() 就会被执行,除非该 activity 是被用户主动销毁的,例如当用户按 BACK 键的时候。

注意上面的双引号,何为"容易"?意思就是说该 activity 还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个 activity 的所有生命周期的 onXXX 方法,包括 onSaveInstanceState() 和 onRestoreInstanceState() 方法,我们可以清楚地知道当某个 activity(假定为 activity A)显示在当前 task 的最上层时,其 onSaveInstanceState() 方法会在什么时候被执行,有这么几种情况:

  • 当用户按下 HOME 键时

这是显而易见的,系统不知道你按下 HOME 后要运行多少其他的程序,自然也不知道 activity A 是否会被销毁,因此系统会调用 onSaveInstanceState() ,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

  • 长按 HOME 键,选择运行其他的程序时
  • 按下电源按键(关闭屏幕显示)时
  • 从 activity A 中启动一个新的 activity 时
  • 屏幕方向切换时,例如从竖屏切换到横屏时

在屏幕切换之前,系统会销毁 activity A,在屏幕切换之后系统又会自动地创建 activity A,所以 onSaveInstanceState() 一定会被执行,且也一定会执行 onRestoreInstanceState()。

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

onRestoreInstanceState() 什么时候调用

onRestoreInstanceState() 被调用的前提是,activity A 确实 被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示 activity A 的时候,用户按下 HOME 键回到主界面,然后用户紧接着又返回到 activity A,这种情况下 activity A 一般不会因为内存的原因被系统销毁,故 activity A 的 onRestoreInstanceState 方法不会被执行 此也说明上二者,大多数情况下不成对被使用。

onRestoreInstanceState()onStart()onPostCreate(Bundle) 之间调用。

onSaveInstanceState() 方法的默认实现

如果我们没有覆写 onSaveInstanceState() 方法,此方法的默认实现会自动保存 activity 中的某些状态数据,比如 activity 中各种 UI 控件的状态.。android 应用框架中定义的几乎所有 UI 控件都恰当的实现了 onSaveInstanceState() 方法,因此当 activity 被摧毁和重建时,这些 UI 控件会自动保存和恢复状态数据。

比如 EditText 控件会自动保存和恢复输入的数据,而 CheckBox 控件会自动保存和恢复选中状态.开发者只需要为这些控件指定一个唯一的 ID(通过设置 android:id 属性即可),剩余的事情就可以自动完成了.如果没有为控件指定 ID,则这个控件就不会进行自动的数据保存和恢复操作。

由上所述,如果我们需要覆写 onSaveInstanceState() 方法,一般会在第一行代码中调用该方法的默认实现: super.onSaveInstanceState(outState)

是否需要重写 onSaveInstanceState() 方法

既然该方法的默认实现可以自动的保存 UI 控件的状态数据,那什么时候需要覆写该方法呢?

如果需要保存额外的数据时,就需要覆写 onSaveInstanceState() 方法。大家需要注意的是: onSaveInstanceState() 方法只适合保存瞬态数据,比如 UI 控件的状态,成员变量的值等,而不应该用来保存持久化数据,持久化数据应该当用户离开当前的 activity 时,在 onPause() 中保存(比如将数据保存到数据库或文件中)。说到这里,还要说一点的就是在 onPause() 中不适合用来保存比较费时的数据,所以这点要理解。

由于 onSaveInstanceState() 方法方法不一定会被调用,因此不适合在该方法中保存持久化数据,例如向数据库中插入记录等. 保存持久化数据的操作应该放在 onPause() 中。若是永久性值,则在 onPause() 中保存;若大量,则另开线程吧,别阻塞 UI 线程。

示例

我一般不习惯调用 onRestoreInstanceState 方法,而比较习惯在 onCreate 方法直接处理。

public class MainActivity extends Activity {
    private String message = "";
    private EditText text = null;
    private Button button = null;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        text = (EditText) findViewById(R.id.editText1);
        button = (Button) findViewById(R.id.btnSave);

        if (savedInstanceState != null)
            message = savedInstanceState.getString("message");
        
        button.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "保存", Toast.LENGTH_SHORT).show();
            }
        });
    }
 
    @Override
    public void onResume(){
        super.onResume();
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
    }
 
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState){
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putString("message", text.getText().toString());
    }
}

以上示例直接在 onCreate 方法中判断 savedInstanceState 是否为空,和直接在 onRestoreInstanceState 方法中处理作用一样。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

剧终人散尽

暂无简介

0 文章
0 评论
24 人气
更多

推荐作者

我们的影子

文章 0 评论 0

素年丶

文章 0 评论 0

南笙

文章 0 评论 0

18215568913

文章 0 评论 0

qq_xk7Ean

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文