1. 程式人生 > 實用技巧 >Android 異常情況下的生命週期分析

Android 異常情況下的生命週期分析

異常情況下的生命週期分析

一:資源相關的系統配置發生改變導致Activity被殺死並重新建立(以旋轉螢幕為例)

樣例程式碼,

首先再onSaveInstanceState中儲存一個字串,然後當 Activity被銷燬並重新建立的時後,再去獲取之前儲存的字串。接收的位置可以在 onRestoreInstanceState 或者onCreate,二者的區別是: onRestoreInstanceState 一旦被呼叫其引數Bundle savedInstanceState一定是有值的,不需要額外判空;但onCreate不行,因為onCreate如果是正常啟動,其引數Bundle savedInstanceState

null,所以必須進行額外判斷。官方推薦採用 onRestoreInstanceState 進行恢復資料。

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState != null){
            String test = savedInstanceState.getString("test");
            Log.d(TAG, "[onCreate] restore extra_test: " + test);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);
        Log.d(TAG,"onSaveInstanceState");
        outState.putString("test","test");
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String test = savedInstanceState.getString("test");
        Log.d(TAG,"[onRestoreInstanceState] restore test: " + test);
    }

當旋轉屏幕後,執行的日誌如下:

日誌分析

當系統配置發生改變後,Activity 會被銷燬,其onPause、onStop、onDestroy 均會被呼叫,同時由於Activity 是在異常情況下終止的,系統會呼叫 onSaveInstanceState 來儲存當前Activity的狀態。這個方法的呼叫時機是在 onStop 之前,它和 onPause 沒有既定的時序關係,它既可能在onPause之前呼叫,也可能在onPause之後呼叫。(當Android api為28時,onStop會在其之前,即 onSaveInstanceState 出現在 onStop之後,onDestroy之前,與日誌情況相符

)需要強調的一點是,這個方法只會出現在Activity 被異常終止的情況下,正常情況下系統不會回撥這個方法。當 Activity 被重新建立後,系統會呼叫 onRestoreInstanceState, 並且把Activity 銷燬時onSavelnstanceState 方法所儲存的Bundle 物件作為引數同時傳遞給 onRestoreInstanceState和 onCreate 方法。因此,我們可以通過 onRestoreInstanceState 和 onCreate 方法來判斷Activity是否被重建了,如果被重建了,那麼我們就可以取出之前儲存的資料並恢復,從時序上來說,onRestorelnstanceState 的呼叫時機在onStart之後。

onSaveInstanceState呼叫時機

  1. 當用戶按下HOME鍵時。 這是顯而易見的,系統不知道你按下HOME後要執行多少其他的程式,自然也不知道activity A是否會被銷燬,故系統會呼叫onSaveInstanceState,讓使用者有機會儲存某些非永久性的資料。以下幾種情況的分析都遵循該原則
  2. 長按HOME鍵,選擇執行其他的程式時
  3. 按下電源按鍵(關閉螢幕顯示)時
  4. 從activity A中啟動一個新的activity時
  5. 螢幕方向切換時,例如從豎屏切換到橫屏時。

onSaveInstanceState的呼叫遵循一個重要原則,即當系統“未經你許可”時銷燬了你的activity,則onSaveInstanceState會被系統呼叫,這是系統的責任,因為它必須要提供一個機會讓你儲存你的資料(當然你不儲存那就隨便你了)

避免當系統配置發生改變後,Activity被重新建立

configChanges屬性新增值

例如解決旋轉螢幕的重新建立:android:configChanges="orientation|screenSize"

主要使用的幾個值

  • keyboardHidden : 鍵盤的可訪問性發生了改變,例如調出了鍵盤
  • orientation : 螢幕方向發生了改變,例如旋轉了螢幕
  • screenSize : 當螢幕的尺寸資訊發省了改變,當旋轉螢幕時,螢幕尺寸會發生改變,但這個選項比較特殊和編譯選項有關,當編譯選項中的 minSdkVersion 和 targetSdkVersion 均低於13時,此選項不會導致 Activity 重啟,否則會導致 Activity 重啟(API 13 新新增)
  • locale : 裝置的本地位置發生了改變,一般指切換了系統語言

二:資源記憶體不足情況導致低優先順序的Activity被殺死

這種情況我們不好模擬,但是其資料儲存和恢復過程和情況一完全一致。這裡我們描述一下Activity的優先順序情況。Activity 按照優先順序從高到低,可以分為如下三種:

  1. 前臺Activity-- 正在和使用者互動的Activity, 優先順序最高。

  2. 可見但非前臺Activity——比如 Activity中彈出了一個對話方塊,導致Activity可見,但是位於後臺無法和使用者直接互動。

  3. 後臺Activity--已經 被暫停的Activity,比如執行了onStop, 優先順序最低。

當系統記憶體不足時,系統就會按照上述優先順序去殺死目標 Activity 所在的程序,並在後續通過 onSaveInstanceState 和 onRestoreInstanceState 來儲存和恢復數資料。如果一個程序中沒有四大元件在執行,那麼這個程序將很快被系統殺死,因此,一些後臺工作不適合脫離四大元件而獨自執行在後臺中,這樣程序很容易被殺死。比較好的方法是將後臺工作放入Service中從而保證程序有一定的優先順序,這樣就不會輕易地被系統殺死。