Android InstanceState

发布于 2024-03-26 10:41:03 字数 5321 浏览 22 评论 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技术交流群

发布评论

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

关于作者

剧终人散尽

暂无简介

文章
评论
28 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

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