一、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 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控件的信息都会被保存,必须满足两个条件
  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控件才会被保存







更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. android检测新版本并下载安装的方法
  4. Android之BaseAdapter的使用
  5. Android中常用的设计模式(一)
  6. Android面试题集锦之Service生命周期
  7. Android消息机制(三):Looper
  8. Android数据储存——Sqlite
  9. IntentService原理

随机推荐

  1. android m classpath
  2. item_dropdown
  3. Android面试(13): Android(安卓)中返回数
  4. Android(安卓)Oreo 常见问题 2.0 | Andro
  5. android LinearLayout布局
  6. Android Helper 帮助类
  7. android - ANR keyDispatchingTimedOut
  8. android 分辨率标题栏及状态栏高度
  9. 自制表盘
  10. android 布局 GridLayout