您的位置:首页 > 其它

深入理解onSaveInstanceState & onRestoreInstanceState 方法

2014-10-15 20:34 633 查看

一、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()方法方法恢复数据,具体此过程的顺序如下:

Activity销毁之前先调用onSaveInstanceState函数保存Activity的状态信息(saveHierarchyState 和saveAllState)和用户保存的数据

调用onCreate()方法restoreAllState,恢复allstate所有状态信息

调用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 before
onStop
.
There are no guarantees about whether it will occur before or after
onPause
.

那调用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中,保存的数据有两种,

Window 的 HierarchyState,可以理解为窗口的阶级状态,里面包含的数据已经打印在上面的图片中,其实也就是一些panels,一些包含ID的UI控件,还有一些ActionBar等信息,还包括一些用户自己保存的信息,这个下面再说到
用一个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 in
onSaveInstanceState
.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控件的信息都会被保存,必须满足两个条件

该UI控件有ID
该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 of
onRestoreInstanceState
).


由此可以重新总结:

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

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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: