Android之什麼時候呼叫onSaveInstance方法的時候(為什麼按Home鍵盤會呼叫,按Back不呼叫)
阿新 • • 發佈:2019-01-31
1、函式介紹
1)、onCreate(Bundle savedInstanceState) 方法
Activity 建立時回撥 : 該方法會自動傳入一個 Bundle 物件, 該 Bundle 物件就是上次被系統銷燬時在 onSaveInstanceState 或者 onRestoreInstanceState 中儲存的資料-- 注意 : 只有是系統自動回收的時候才會儲存 Bundle 物件資料;
-- Bundle 物件來源 : onCreate() 方法中的 Bundle 物件引數, 是在 onSaveInstance() 或者 onRestoreInstanceState() 方法中儲存的 Bundle 物件;
2)、 onSaveInstanceState(Bundle outState) 方法
outState 引數作用 :
資料儲存 : Activity 宣告週期結束的時候, 需要儲存 Activity 狀態的時候, 會將要儲存的資料使用鍵值對的形式 儲存在 Bundle 物件中;
恢復資料 : 在 Activity 的 onCreate()方法 建立 Activity 的時候會傳入一個 Bundle 物件, 這個 Bundle 物件就是這個 outState 引數;
呼叫時機 : Activity 容易被銷燬的時候呼叫, 注意是容易被銷燬, 也可能沒有銷燬就呼叫了; 按下Home鍵 : Activity 進入了後臺, 此時會呼叫該方法;
按下電源鍵 : 螢幕關閉, Activity 進入後臺;
啟動其它 Activity : Activity 被壓入了任務棧的棧底;
橫豎屏切換 : 會銷燬當前 Activity 並重新建立; onSaveInstanceState方法呼叫注意事項 :
使用者主動銷燬不會呼叫 : 當用戶點選回退鍵 或者 呼叫了 finish() 方法, 不會呼叫該方法;
呼叫時機不固定 : 該方法一定是在 onStop() 方法之前呼叫, 但是不確定是在 onPause() 方法之前 還是 之後呼叫;
佈局中元件狀態儲存 : 每個元件都 實現了 onSaveInstance() 方法, 在呼叫函式的時候, 會自動儲存元件的狀態, 注意, 只有有 id 的元件才會儲存;
關於預設的 super.onSaveInstanceState(outState) : 該預設的方法是實現 元件狀態儲存的;
(3) onRestoreInstanceState(Bundle savedInstanceState) 方法
-- Bundle 物件傳遞 : 該方法儲存的 Bundle 物件在 Activity 恢復的時候也會通過引數傳遞到 onCreate() 方法中;
2、原始碼分析呼叫onSaveInstance函式的時候
1)、看下ActivityThread.handlePauseActivity的原始碼private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { ActivityClientRecord r = mActivities.get(token); if (r != null) { //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r); if (userLeaving) { performUserLeavingActivity(r); } r.activity.mConfigChangeFlags |= configChanges; performPauseActivity(token, finished, r.isPreHoneycomb()); // Make sure any pending writes are now committed. if (r.isPreHoneycomb()) { QueuedWork.waitToFinish(); } // Tell the activity manager we have paused. if (!dontReport) { try { ActivityManagerNative.getDefault().activityPaused(token); } catch (RemoteException ex) { } } mSomeActivitiesChanged = true; } }
再看performPauseActivity方法
final Bundle performPauseActivity(IBinder token, boolean finished,
boolean saveState) {
ActivityClientRecord r = mActivities.get(token);
return r != null ? performPauseActivity(r, finished, saveState) : null;
}
再看掉用過載方法performPauseActivityfinal Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState) {
...
if (!r.activity.mFinished && saveState) {
callCallActivityOnSaveInstanceState(r);
}
...
}
我們知道呼叫callCallActivityOnSaveInstanceState方法,看名稱發現這裡應該回調的是Activity的onSaveInstanceState方法,我們再看掉用這個函式的條件
!r.activity.mFinished && saveState
如果activity沒有掉用finish()
方法,mFinished的值就是false,如果需要進入這個函式,就需要後面的值saveState值為0,這裡的saveState是performPauseActivity方法傳遞過來的
performPauseActivity(token, finished, r.isPreHoneycomb());
我們再看函式r.isPreHoneycomb
public boolean isPreHoneycomb() {
if (activity != null) {
return activity.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.HONEYCOMB;
}
return false;
}
App設定的targetSdk版本號小於android
versionCode 11也就是android3.0的時候返回為true,其他的時候返回為false,也就是說當我們App設定的targetVersion大於android3.0的時候才會執行callCallActivityOnSaveInstanceState方法,然後接著看callCallActivityOnSaveInstanceState方法,如下
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
r.state = new Bundle();
r.state.setAllowFds(false);
if (r.isPersistable()) {
r.persistentState = new PersistableBundle();
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
}
}
我們再去Instrumentation.java裡面去看函式callActivityOnSaveInstanceState
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
PersistableBundle outPersistentState) {
activity.performSaveInstanceState(outState, outPersistentState);
}
我們再去Activity.java裡面去看函式performSaveInstanceState實現
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}
可以看到這裡掉用了Activity的onSaveInstanceState方法,這樣經過一系列的方法回撥之後就執行了onSaveInstanceState方法。接下來我們看下onStop方法是否會執行onSaveInstanceState方法,同理Actvitiy執行onStop方法會回撥ActivityThread的handleStopActivity
接下來我們看handleStopActivity方法的實現:
private void handleStopActivity(IBinder token, boolean show, int configChanges) {
ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
StopInfo info = new StopInfo();
performStopActivityInner(r, info, show, true);
if (localLOGV) Slog.v(
TAG, "Finishing stop of " + r + ": show=" + show
+ " win=" + r.window);
updateVisibility(r, show);
info.activity = r;
info.state = r.state;
info.persistentState = r.persistentState;
mH.post(info);
mSomeActivitiesChanged = true;
}
我們再來看方法performStopActivityInner實現
private void performStopActivityInner(ActivityClientRecord r,
StopInfo info, boolean keepShown, boolean saveState) {
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
callCallActivityOnSaveInstanceState(r);
}
}
if (!keepShown) {
try {
// Now we are idle.
r.activity.performStop();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to stop activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.stopped = true;
}
我們知道saveState穿進去為true,只要mFinished不是true就一定進入這個方法,所以只要在mFinished不為true,也就是沒有呼叫finish()函式的前提下,就一定執行onSaveInstanceState方法,所以當App設定的targetVersion大於android3.0,沒有呼叫finish函式的情況下,一定會呼叫onSaveInstanceState方法後再去呼叫onStop方法。
3、為什麼按Home鍵盤會掉用onSaveInstance方法儲存資料,按Back不掉用onSaveInstance方法儲存資料
因為按下Home鍵盤沒有呼叫 finish函式,如果targetVersion大於Androi3.0就一定執行onSaveInstanceState方法,所以就儲存資料了,如果按下返回鍵,會呼叫 finish方法,所有mFinished為true,所以不會掉用onSaveInstanceState方法,所以不會儲存資料。
4、手機常見操作Activity生命週期狀態變化來驗證
寫了一個簡單的Activity,在每個Activity周期函式裡面列印了相關的執行函式資訊
1)、啟動Activity
2)、按下電源或者Home鍵
3)、按亮電源鍵或者點選專案(一開啟按了Home鍵)
4)、按下返回鍵(back鍵盤)
5、總結
1、onSaveInstanceState方法是Activity的生命週期方法,主要用於在Activity銷燬時儲存一些資訊。2、當Activity只執行onPause方法時(Activity a開啟一個透明Activity b)這時候如果App設定的targetVersion大於android3.0則不會執行onSaveInstanceState方法。
3、當Activity執行onStop方法時,通過分析原始碼我們知道只要Activity沒有執行finish函式一定會呼叫onSaveInstanceState的方法,然後再去掉用onStop方法。
onPause() -> onSaveInstanceState() -> onStop()