Android之什么時候調用onSaveInstance方法的時候(為什么按Home鍵盤會調用,按Back不調用)


1、函數介紹


1)、onCreate(Bundle savedInstanceState) 方法

Activity 創建時回調 : 該方法會自動傳入一個 Bundle 對象, 該 Bundle 對象就是上次被系統銷毀時在 onSaveInstanceState 或者 onRestoreInstanceState 中保存的數據
-- 注意 : 只有是系統自動回收的時候才會保存 Bundle 對象數據;
-- Bundle 對象來源 : onCreate() 方法中的 Bundle 對象參數, 是在 onSaveInstance() 或者 onRestoreInstanceState() 方法中保存的 Bundle 對象;

2)、 onSaveInstanceState(Bundle outState) 方法

onSaveInstanceState函數是Activity的生命周期函數
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) 方法

方法回調時機 : 在 Activity 被系統銷毀之后 恢復 Activity 時被調用, 只有銷毀了之后重建的時候才調用, 如果內存充足, 系統沒有銷毀這個 Activity, 就不需要調用;
-- 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;
    }

再看掉用重載方法 performPauseActivity
final 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()





注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: