深入理解onSaveInstanceState函数与onRestoreInstanceState函数

从网上看到一篇Acitivity状态保存和恢复很好的文章,讲得很透彻和实用。

一、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控制項才會被保存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值