现在的位置: 首页 > 综合 > 正文

深入理解onSaveInstanceState & onRestoreInstanceState 方法

2015年06月12日 ⁄ 综合 ⁄ 共 4073字 ⁄ 字号 评论关闭

一、onSaveInstanceState 函数与onRestoreInstanceState 函数的作用


onSaveInstanceState 函数:用于保存Activity的状态信息(UI控件的状态信息)和用户保存的信息

onRestoreInstanceState函数:用于恢复Activity被系统销毁时的状态信息和用户保存的信息

二、onSaveInstanceState
函数的调用时间


1、当用户按下HOME键时

2、长按HOME键,选择运行其他的程序时

3、按下电源按键(关闭屏幕显示)时

4、从activity
A中启动一个新的activity时

5、屏幕方向切换时,例如从竖屏切换到横屏时

  • 当系统销毁一个Activity的时候,onSaveInstanceState方法会被调用,如内存不足、用户直接按Home键等,当如果是用户按返回键,则不会调用onSaveInstanceState方法,因为系统觉得没必要保存数据

  • 如果我们没有复写onSaveInstanceState()方法, 此方法的默认实现会自动保存activity中的某些状态数据,
    比如activity中各种UI控件的状态
  • 如果我们需要覆写onSaveInstanceState()方法,
    一般会在第一行代码中调用该方法的默认实现:
    super.onSaveInstanceState(outState)

    三、存储数据和恢复数据原理

  • 屏幕方向切换时,Activity被系统销毁后重新建立,此时会调用onSaveInstanceState函数保存数据,待屏幕切换完成后,会调用onCreate()方法和onRestoreInstanceState()方法方法恢复数据,具体此过程的顺序如下:

    1. Activity销毁之前先调用onSaveInstanceState函数保存Activity的状态信息(saveHierarchyState 和saveAllState)和用户保存的数据
    2. 调用onCreate()方法restoreAllState,恢复allstate所有状态信息
    3. 调用onRestoreInstanceState()方法restoreHierarchyState恢复阶级调用信息
  • 我们是从何得知这个顺序的呢,还得从Activity的生命周期以及使用LogCat得出,观看下面LogCat数据,为切换屏幕方向时的LogCat信息

  • 可以看到,切换屏幕时上述函数的调用顺序是onPause -->onSaveInstanceState-->onStop-->onDestory-->onCreate(切换屏幕后重新创建Activity时调用的onCreate方法)-->onStart-->onRestoryInstanceState-->onResume
  • 依照android官方源码的解释,onSaveInstanceState方法一定是在onStop方法之前调用,但不保证在onPause方法之前或之后调用,官方源码解释如下:If called, this method will occur beforeonStop.
    There are no guarantees about whether it will occur before or afteronPause.
  • 那调用onSaveInstanceState方法保存Activity状态数据的时候究竟是保存了哪些东西呢?查看onSaveInstanceState函数的源代码就知道了
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }
  • 由上面的android源码可以看到,其实也是保存的到Bundle中,保存的数据有两种,

  1. Window 的 HierarchyState,可以理解为窗口的阶级状态,里面包含的数据已经打印在上面的图片中,其实也就是一些panels,一些包含ID的UI控件,还有一些ActionBar等信息,还包括一些用户自己保存的信息,这个下面再说到
  2. 用一个Paracelable 对象保存 Fragment的所有状态,再将这个Paracelable对象添加到Bundle对象中
  • 恢复数据时调用了onCreate方法,onCreate方法源代码如下
    protected void onCreate(Bundle savedInstanceState) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
        if (mLastNonConfigurationInstances != null) {
            mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
        }
        if (mActivityInfo.parentActivityName != null) {
            if (mActionBar == null) {
                mEnableDefaultActionBarUp = true;
            } else {
                mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
            }
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate();
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        mCalled = true;
    }
  • 由上面的源代码可以看出,onCreate方法恢复数据时是恢复了Paracelable对象下的Fragment的allstate,前提是 saveInstanceState!=null ,这个条件一般不容易满足,只有在Activity被系统销毁时,onCreate方法中的参数saveInstanceState才不会空,否则就算调用了onsaveInstanceState方法,onCreate方法中的参数saveInstanceState也依旧是null,这点可以从源代码的注释中得出
Parameters:
savedInstanceState If the activity is being re-initialized after previously being shut down then this Bundle contains the data it most recently supplied inonSaveInstanceState.Note:
Otherwise it is null

  • 调用了onCreate方法之后,系统再调用onRestoryInstanceState方法恢复数据,onRestoryInstanceState方法的源代码如下:
   protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mWindow != null) {
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
                mWindow.restoreHierarchyState(windowState);
            }
        }
    }

  • 由上面的源代码可以看出,onRestoryInstanceState函数恢复的数据是HierarchyState
  • 再重新说一下onSaveInstanceState方法中保存的数据,其中有一项是UI控件的ID,并不是所有的UI控件的信息都会被保存,必须满足两个条件
  1. 该UI控件有ID
  2. 该UI空间当前获得焦点,即被点击到
  • 这两个条件也可以从源代码的注释中得出,而且可以写一个Demo证明这种这种解释是对的
The default implementation takes care of most of the UI per-instance state
for you by calling
android.view.View.onSaveInstanceState() on each view in the hierarchy that has
an id
, and by saving the id of the currently focused view (all of which is restored by the default implementation ofonRestoreInstanceState).
 

  • 由此可以重新总结:
  1. 当Activity被系统撤销后重新建立时,保存以及恢复数据的函数调用顺序是:onSaveInstanceState(保存数据)-->onCreate(恢复数据allstate)-->onRestoryInstanceState(恢复数据HierarchyState)
  2. onSaveInstanceState函数保存的数据时:View.HierarchyState
    ,即panels,UI控件,ActionBar等

  3. 保存的UI控件必须是包含ID的,而且是当前获得焦点的UI控件才会被保存


抱歉!评论已关闭.