活動生命週期階段

1. 事前準備

在本程式碼研究室中,您將瞭解 Android 的基本要素:活動生命週期

在其生命週期中,活動會透過不同狀態轉換,有時還會返回各狀態。此狀態轉換稱為活動生命週期。

在 Android 中,活動是與使用者互動的進入點。

過去,一項活動會在應用程式中顯示一個螢幕。根據目前的最佳做法,其中一項活動可能會依需求切換不同螢幕,以顯示多個畫面。

當系統回收該活動的資源時,活動生命週期會從建立活動延伸至刪除。當使用者進入及退出活動時,每個活動會在活動生命週期中的不同狀態之間進行轉換。

身為 Android 開發人員,您必須瞭解活動生命週期。如果您的活動未正確回應生命週期狀態變更,應用程式可能會產生異常錯誤、造成使用者混淆行為,或耗用過多 Android 系統資源。瞭解 Android 生命週期,並正確回應生命週期狀態變更,是 Android 開發作業中重要的一環。

必要條件

  • 瞭解什麼是活動,以及在應用程式中建立活動的方式
  • 瞭解活動的 onCreate() 方法用途,以及該方法執行的運算種類

課程內容

  • 如何將記錄資訊列印至 Logcat
  • Activity 生命週期的基本概念,以及活動於狀態之間變動時叫用的回呼。
  • 如何覆寫生命週期回呼方法,以在活動生命週期的不同時間點執行運算。

建構項目

  • 修改名為 Dessert Clicker 的範例應用程式,新增顯示在 Logcat 中的記錄資訊。
  • 覆寫生命週期回呼方法,並記錄活動狀態的變更。
  • 執行應用程式,並記下活動開始、停止和繼續時的記錄資訊。
  • 實作 rememberSaveable,保留因裝置設定變更而可能遺失的應用程式資料。

2. 應用程式總覽

在本程式碼研究室中,您將使用名為 Dessert Clicker 的範例應用程式。在 Dessert Clicker 中,每當使用者輕觸螢幕上的甜點,應用程式就會為使用者「購買」甜點。應用程式會在版面配置中更新下列項目的值:

  • 「已購買」甜點的數量
  • 「已購買」甜點的總收益

245d0bdfc09f4d54.png

此應用程式含有多個與 Android 生命週期相關的錯誤。例如,在某些情況下,應用程式會將甜點值重設為 0。瞭解 Android 生命週期有助於瞭解問題發生的原因與修正方法。

下載範例程式碼

在 Android Studio 中開啟 basic-android-kotlin-compose-training-dessert-clicker 資料夾。

3. 探索生命週期方法並新增基本記錄

每個活動都具有生命週期。這個詞類比的是動植物的生命週期,比如蝴蝶的生命週期,就是指從卵、毛毛蟲、蛹到成蝶和死亡的不同成長階段狀態。

蝴蝶生命週期 - 從卵、毛毛蟲、蛹到成蝶和死亡的成長過程。

同樣地,活動生命週期包含活動從首次初始化到刪除之間可能經歷的不同狀態,而作業系統 (OS) 會在活動刪除時回收其記憶體。一般來說,程式的進入點為 main() 方法。不過,Android 活動會先使用 onCreate() 方法。此方法等同於上述範例中的卵子階段。在本課程中,您已多次使用活動,您可能會認得 onCreate() 方法。當使用者啟動您的應用程式、在活動間瀏覽、在應用程式內部或外部瀏覽時,活動皆會改變狀態。

下圖顯示所有活動生命週期狀態。顧名思義,這些狀態代表活動的狀態。請注意,與蝴蝶生命週期不同的是,活動在整個生命週期中來回切換,而不是只朝單一方向移動。

ca808edb1c95f07a.png

通常,當活動生命週期狀態變更時,您會想變更部分行為或執行某些程式碼。因此,Activity 類別本身和 Activity 的任何子類別 (例如 ComponentActivity) 會實作一系列生命週期回呼方法。當活動狀態改變時,Android 將會叫用這些回呼,而您可以在自身活動中覆寫此類方法,以執行回應生命週期狀態變更的工作。下圖顯示生命週期狀態,以及可用的可覆寫回呼。

活動生命週期圖表

請務必瞭解 Android 何時叫用可覆寫的回呼,以及每個回呼方法的處理方式,但這兩個圖表都很複雜,可能會混淆。在本程式碼研究室中,您將需要進行一些偵測工作並對 Android 活動生命週期建立一定的瞭解,而不只是瞭解每個狀態和回呼的意義。

步驟 1:檢查 onCreate() 方法並新增記錄

如要瞭解 Android 生命週期發生的情況,瞭解呼叫各種生命週期方法的時機相當實用。這項資訊可協助您在 Dessert Clicker 應用程式中找出問題所在。

要判斷這項資訊,最簡單的方法是使用 Android 記錄功能。記錄功能可讓您在應用程式執行期間,將簡短訊息寫入主控台,用於查看不同回呼的觸發時機。

  1. 執行 Dessert Clicker 應用程式,然後在甜點相片上輕觸數次。請注意,已售出甜點值和總金額的變化情況。
  2. 開啟 MainActivity.kt 並檢查此活動的 onCreate() 方法:
override fun onCreate(savedInstanceState: Bundle?) {
    // ...
}

在活動生命週期圖表中,您可能認出 onCreate() 方法,因為您先前曾使用此回呼。這是每項活動都必須實作的方法。onCreate() 是您為活動執行任何一次性初始化作業的方法。舉例來說,在 onCreate() 中呼叫 setContent(),即可指定活動的 UI 版面配置。

onCreate 生命週期方法

OS 在記憶體中建立新的 Activity 物件時,活動會「初始化」,之後系統就會呼叫一次 onCreate() 生命週期方法。執行 onCreate() 後,系統會將活動視為「已建立」

  1. MainActivity.kt 頂層的類別宣告 class MainActivity 的上方新增下列常數。

建議您在檔案中宣告 TAG 常數,因為該值的值不會改變。

如要將其標示為編譯時間常數,請在宣告變數時使用 const。編譯時間常數是編譯期間已知的值。

private const val TAG = "MainActivity"
  1. onCreate() 方法中,於呼叫 super.onCreate() 後新增下列程式碼:
Log.d(TAG, "onCreate Called")
  1. 視需要匯入 Log 類別,方法為按下 Alt+Enter 鍵 (Mac 上為 Option+Enter 鍵),然後選取「Import」。如果您已啟用自動匯入功能,系統會自動執行這項操作。
import android.util.Log

Log 類別會將訊息寫入「Logcat」。「Logcat」是記錄訊息的主控台。此處會顯示來自 Android 的應用程式相關訊息,包括您透過 Log.d() 方法或其他 Log 類別方法明確傳送至記錄的訊息。

Log 指示有三個重要面向:

  • 記錄訊息的優先順序是指訊息的重要性。在本例中,Log.v() 會記錄詳細訊息。Log.d() 方法會寫入偵錯訊息。Log 類別中的其他方法包括用於參考性訊息的 Log.i()、用於警示訊息的 Log.w(),以及用於錯誤訊息的 Log.e()
  • 在本例中,記錄 tag (第一個參數) 為 "MainActivity"。這個標記是字串,能讓您更輕鬆在 Logcat 中找到記錄訊息。標記通常是類別的名稱。
  • 實際記錄訊息 msg (第二個參數) 則是簡短字串,在本例中為 "onCreate Called"

a4ff4aa74384ff6.png

  1. 編譯並執行 Dessert Clicker 應用程式。您輕觸甜點時,不會在應用程式中看到任何行為差異。在 Android Studio 中,按一下畫面底部的「Logcat」分頁標籤。

ed03d4bb1f020995.png

  1. 在「Logcat」視窗的搜尋欄位中輸入 tag:MainActivity

961ea44c4b9ee3c.png

Logcat 可包含許多訊息,其中大部分對您皆不適用。篩選 Logcat 項目的方法相當多樣,但搜尋是最簡單的方法。由於您在程式碼中使用 MainActivity 做為記錄標記,因此您可以使用該標記篩選記錄。記錄訊息會包含日期和時間、記錄標記、套件名稱 (com.example.dessertclicker) 和實際訊息。當訊息出現在記錄中,表示系統已執行該 onCreate()

步驟 2:實作 onStart() 方法

系統將在 onCreate() 之後呼叫 onStart() 生命週期方法。onStart() 開始執行後,螢幕上會顯示您的活動。系統只能呼叫一次 onCreate() 來初始化活動,但系統可能會在活動生命週期中多次呼叫 onStart()

a357d2291de472d9.png

請注意,onStart() 和對應的 onStop() 生命週期方法配對。如果使用者啟動應用程式,然後返回裝置的主畫面,活動就會停止,且不再顯示於螢幕上。

  1. 在 Android Studio 中開啟 MainActivity.kt,將游標移至 MainActivity 類別內,然後依序選取「Code」>「Override Methods...」,或按下 Control+O 鍵。畫面上會顯示對話方塊,列出可在此類別中覆寫的所有方法。

11ff93bee1c3940f.png

  1. 開始輸入 onStart 以搜尋正確方法。如要捲動至下一個相符的項目,請使用向下鍵。從清單中選擇 onStart(),然後按一下確定,以插入樣板覆寫程式碼。程式碼如下所示:
override fun onStart() {
    super.onStart()
}
  1. onStart() 方法中加入記錄訊息:
override fun onStart() {
    super.onStart()
    Log.d(TAG, "onStart Called")
}
  1. 編譯並執行 DessertClicker 應用程式,然後開啟Logcat窗格。
  2. 在搜尋欄位中輸入 tag:MainActivity,以篩選記錄。請注意,系統將逐一呼叫 onCreate()onStart() 方法,活動也會顯示在畫面上。
  3. 按下裝置的「主畫面」按鈕,然後使用「最近使用」畫面返回活動。請注意,活動會從上次中斷的地方接續進行,所有值皆相同,且 onStart() 會再次記錄到 Logcat。另請注意,系統不會再次呼叫 onCreate() 方法。
2024-02-20 10:30:00.231  5684-5684  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-02-20 10:30:00.278  5684-5684  MainActivity            com.example.dessertclicker           D  onStart Called
2024-02-20 10:30:39.020  5684-5684  MainActivity            com.example.dessertclicker           D  onStart Called

步驟 3:新增更多記錄陳述式

在這個步驟中,您會實作所有其他生命週期方法的記錄功能。

  1. 覆寫 MainActivity 中的其餘生命週期方法,並為每個方法新增記錄陳述式,如以下程式碼所示:
override fun onResume() {
    super.onResume()
    Log.d(TAG, "onResume Called")
}

override fun onRestart() {
    super.onRestart()
    Log.d(TAG, "onRestart Called")
}

override fun onPause() {
    super.onPause()
    Log.d(TAG, "onPause Called")
}

override fun onStop() {
    super.onStop()
    Log.d(TAG, "onStop Called")
}

override fun onDestroy() {
    super.onDestroy()
    Log.d(TAG, "onDestroy Called")
}
  1. 再次編譯並執行 Dessert Clicker,並檢查 Logcat。

請注意,除了 onCreate()onStart() 以外,這次系統也會提供 onResume() 生命週期回呼的記錄訊息。

2024-02-20 10:33:36.033  5789-5789  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-02-20 10:33:36.073  5789-5789  MainActivity            com.example.dessertclicker           D  onStart Called
2024-02-20 10:33:36.075  5789-5789  MainActivity            com.example.dessertclicker           D  onResume Called

活動從頭開始時,系統會依序呼叫所有三個生命週期回呼:

  • onCreate()當系統建立應用程式時。
  • onStart() 會在螢幕上顯示應用程式,但使用者還無法與該應用程式互動。
  • onResume() 會將應用程式移至前景,而使用者現在可以與應用程式互動。

儘管與方法名稱不盡相符,系統會在活動啟動時呼叫 onResume() 方法,即使沒有要繼續進行的活動也一樣。

活動生命週期圖表

4. 探索生命週期用途

您已經設定 Dessert Clicker 應用程式進行記錄,現在您可以開始使用該應用程式,並探索觸發生命週期回呼的方式。

用途 1:開啟及關閉活動

首先是最基本的用途,也就是首次啟動應用程式,然後關閉應用程式。

  1. 編譯並執行 Dessert Clicker 應用程式 (如果尚未執行)。如您所見,活動初次開始時,就會呼叫 onCreate()onStart(),以及 onResume() 回呼。
2024-02-20 10:33:36.033  5789-5789  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-02-20 10:33:36.073  5789-5789  MainActivity            com.example.dessertclicker           D  onStart Called
2024-02-20 10:33:36.075  5789-5789  MainActivity            com.example.dessertclicker           D  onResume Called
  1. 輕觸杯子蛋糕數次。
  2. 輕觸裝置上的「Back」按鈕。

請注意,Logcat 中會依序呼叫 onPause()onStop()

2024-02-20 10:34:41.974  5789-5789  MainActivity            com.example.dessertclicker           D  onPause Called
2024-02-20 10:34:42.411  5789-5789  MainActivity            com.example.dessertclicker           D  onStop Called

在此情況下,使用「Back」按鈕會導致活動 (和應用程式) 從畫面移除,並移至活動堆疊的背面。

如果程式碼手動呼叫活動的 finish() 方法,或是使用者強制退出應用程式,Android 作業系統可能會關閉活動。舉例來說,使用者可以在「最近使用」畫面中,強制退出或關閉應用程式。若應用程式長時間未處於畫面上,作業系統也可能會自行關閉活動。這樣一來,Android 可以延長電池續航力,並回收應用程式使用的資源,供其他應用程式使用。以上僅列舉 Android 系統刪除活動的幾項原因。在某些其他情況下,Android 系統會刪除活動,但不會發出警告。

用途 2:離開後再返回活動

現在您已啟動並關閉應用程式,因此能看到活動首次建立時大部分的生命週期狀態,以及活動關閉時經歷的大部分生命週期狀態。然而,使用者操作 Android 裝置時,會切換使用不同的應用程式、返回主畫面、啟動新應用程式,並處理因其他活動 (例如來電) 而中斷的活動。

每次使用者離開該活動時,活動都不會完全關閉:

  • 當系統不再於螢幕中顯示活動時,即稱為使活動進入「背景」。反之,則活動位於前景或螢幕上。
  • 使用者返回應用程式時,系統會重新啟動相同活動,並再次顯示該活動。生命週期中的此部分稱為應用程式的可見生命週期。

當應用程式在背景運作時,通常不應主動運作,以節約系統資源和電池壽命。您會使用 Activity 生命週期及其回呼來瞭解應用程式移至背景的時間,以便暫停任何進行中的作業。接著您會在應用程式進入前景時重新開始作業。

在這個步驟中,您可以查看應用程式進入背景後再次回到前景的活動生命週期。

  1. 執行 Dessert Clicker 應用程式時,點選紙杯蛋糕數次。
  2. 按下裝置上的「主畫面」按鈕,然後觀察 Android Studio 中的 Logcat。返回主畫面會讓應用程式進入背景,而非完全關閉應用程式。請注意,系統會呼叫 onPause()onStop() 方法。
2024-02-20 10:35:26.832  5789-5789  MainActivity            com.example.dessertclicker           D  onPause Called
2024-02-20 10:35:27.233  5789-5789  MainActivity            com.example.dessertclicker           D  onStop Called

呼叫 onPause() 後,應用程式就不再有焦點。onStop() 後,應用程式就不會再顯示於螢幕上。儘管活動已經停止,但 Activity 物件仍位於背景的記憶體中。Android 作業系統尚未刪除活動。使用者可能會返回應用程式,因此 Android 會保留您的活動資源。

c470ee28ab7f8a1a.png

  1. 使用「最近使用」畫面返回應用程式。在模擬器中,點選下圖所示的正方形系統按鈕即可存取「最近使用」畫面。

請注意,活動會在 Logcat 中使用 onRestart()onStart() 重新啟動,然後使用 onResume() 繼續執行。

bc156252d977e5ae.png

2024-02-20 10:36:05.837  5789-5789  MainActivity            com.example.dessertclicker           D  onRestart Called
2024-02-20 10:36:05.839  5789-5789  MainActivity            com.example.dessertclicker           D  onStart Called
2024-02-20 10:36:05.842  5789-5789  MainActivity            com.example.dessertclicker           D  onResume Called

當活動返回前景時,就不會再次呼叫 onCreate() 方法。活動物件並未刪除,因此不需要重新建立。系統會呼叫 onRestart() 方法,而不是 onCreate()。請注意,當活動返回前景時,系統會保留售出甜點數量。

  1. 至少啟動一個 Dessert Clicker 以外的應用程式,讓裝置的「最近使用」畫面中有多個應用程式。
  2. 開啟最近使用螢幕,並開啟其他最近活動。接著返回最近使用的應用程式,將 Dessert Clicker 移回前景。

請注意,此處 Logcat 中顯示的回呼與按下「主畫面」按鈕時相同。當應用程式進入背景時,系統會呼叫 onPause()onStop(),並在應用程式返回時呼叫 onRestart()onStart()onResume()

當應用程式停止運作並移至背景,或應用程式重新啟動並返回前景時,系統就會呼叫這些方法。如果遇到這類情況,而您需要在應用程式中執行工作,請覆寫相關的生命週期回呼方法。

用途 3:部分隱藏活動

您已經瞭解應用程式啟動且呼叫 onStart() 時,螢幕上會顯示該應用程式。呼叫 onResume() 時,應用程式會取得使用者焦點,意即使用者可與應用程式互動。當應用程式完全位於螢幕上且具有使用者焦點,這部分的生命週期就稱為前景生命週期

應用程式進入背景時,焦點會於 onPause() 後消失,且應用程式在 onStop() 後也不再顯示。

請務必區分焦點和顯示情形的差異。活動可以「部分」顯示在螢幕上,但沒有使用者焦點。在此步驟中,可看到一種情況,即可部分顯示活動,但沒有使用者焦點。

  1. 在 Dessert Clicker 應用程式執行時,點選畫面右上方的「Share」按鈕。

分享活動會顯示在畫面下半部,但活動仍會在上半部顯示。

677c190d94e57447.pngca6285cbbe3801cf.png

  1. 檢查 Logcat,並留意系統只呼叫 onPause()
2024-02-20 10:36:42.886  5789-5789  MainActivity            com.example.dessertclicker           D  onPause Called

在此用途中,系統不會呼叫 onStop(),因為畫面上仍顯示部分活動。不過,這類活動沒有使用者焦點,且使用者無法與其互動,因為位於前景的「分享」活動具有使用者焦點。

為什麼這個差異很重要?僅使用 onPause() 的干擾通常只會持續一小段時間,然後使用者便會返回活動或前往其他活動或應用程式。一般而言,您需要持續更新 UI,應用程式的其餘部分便不會停止運作。

onPause() 中執行的程式碼會使其他內容無法顯示,因此請將程式碼保存在輕量 onPause() 中。例如,如果有來電,onPause() 中的程式碼可能會延遲來電通知。

  1. 按一下分享對話方塊以外的地方,返回應用程式,並留意系統已呼叫 onResume()

onResume()onPause() 都與焦點有關。活動有焦點時,系統會呼叫 onResume() 方法;活動失去焦點時,就會呼叫 onPause()

5. 探索設定變更

請務必瞭解另一個管理活動生命週期的案例:設定變更對活動生命週期的影響。

設定變更於裝置狀態改變時發生,因此基本上,使系統解決變更的最簡單方法就是完全關閉,然後重新建立活動。舉例來說,若使用者變更裝置語言,您必須調整整個版面配置,以配合不同的文字方向和字串長度。如果使用者將裝置插入座架或新增實體鍵盤,應用程式版面配置可能必須採用不同的顯示大小或版面配置。如果裝置螢幕方向改變 (例如將裝置從直向轉為橫向或向後旋轉),您可能需要根據新的螢幕方向變更版面配置。讓我們看看應用程式在這個情境中的行為。

最後示範的生命週期回呼為 onDestroy(),也就是在 onStop() 之後呼叫。會在活動刪除前呼叫。如果應用程式的程式碼呼叫 finish(),或是系統因設定變更而需刪除並重新建立活動,就會發生這種情況。

設定變更導致必須呼叫 onDestroy()

螢幕旋轉是一種設定變更的類型,會導致關閉活動並重新啟動。如要模擬這項設定變更並檢查其影響,請完成下列步驟:

  1. 編譯並執行應用程式。
  2. 確保模擬器的螢幕旋轉鎖定功能已停用。
  3. 將裝置或模擬器旋轉至橫向模式。您可以使用旋轉按鈕向左或向右旋轉模擬器。
  4. 檢查 Logcat,瞭解在活動關閉時,系統會依序呼叫 onPause()onStop()onDestroy()
2024-02-20 10:37:57.078  5987-5987  MainActivity            com.example.dessertclicker           D  onPause Called
2024-02-20 10:37:57.087  5987-5987  MainActivity            com.example.dessertclicker           D  onStop Called
2024-02-20 10:37:57.102  5987-5987  MainActivity            com.example.dessertclicker           D  onDestroy Called

裝置旋轉時資料遺失

  1. 編譯並執行應用程式,然後開啟 Logcat。
  2. 按數次杯子蛋糕,但請注意,售出甜點和總收益不為零。
  3. 確保模擬器的螢幕旋轉鎖定功能已停用。
  4. 將裝置或模擬器旋轉至橫向模式。您可以使用旋轉按鈕向左或向右旋轉模擬器。

f745d0e2697415fd.png

  1. 檢查 Logcat 中的輸出內容。在 MainActivity 上篩選輸出內容。
2024-02-20 10:39:22.724  6087-6087  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-02-20 10:39:22.752  6087-6087  MainActivity            com.example.dessertclicker           D  onStart Called
2024-02-20 10:39:22.753  6087-6087  MainActivity            com.example.dessertclicker           D  onResume Called
2024-02-20 10:39:40.508  6087-6087  MainActivity            com.example.dessertclicker           D  onPause Called
2024-02-20 10:39:40.540  6087-6087  MainActivity            com.example.dessertclicker           D  onStop Called
2024-02-20 10:39:40.549  6087-6087  MainActivity            com.example.dessertclicker           D  onDestroy Called
2024-02-20 10:39:40.582  6087-6087  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-02-20 10:39:40.584  6087-6087  MainActivity            com.example.dessertclicker           D  onStart Called
2024-02-20 10:39:40.585  6087-6087  MainActivity            com.example.dessertclicker           D  onResume Called

請注意,當裝置或模擬器旋轉螢幕時,系統會呼叫所有生命週期回呼來關閉活動。接著,當您重新建立活動時,系統會呼叫所有生命週期回呼來啟動活動。

當裝置旋轉,系統也關閉並重新建立活動後,活動就會以預設值重新啟動,也就是將甜點圖片、已售出甜點數量和總收益重設為零。

如要瞭解這些值重設的原因以及修正方式,您必須瞭解可組合元件的生命週期,以及其如何觀測及保留其狀態。

可組合函式生命週期

應用程式 UI 最初建立的方法,是在組成程序中執行可組合函式。

應用程式狀態變更時,系統會排定重組作業的時間。在重組過程中,Compose 會重新執行狀態可能已變更的可組合函式,並建立更新版 UI。更新後的組成會反映變更情形。

建立或更新組成的唯一方法,就是執行初始組成和後續重組作業。

可組合函式有自己的生命週期,與活動生命週期無關。可組合函式的生命週期會依以下事件劃分:進入組成、重組 0 次以上、離開組成。

為了讓 Compose 追蹤及觸發重組作業,Compose 需要瞭解狀態何時發生變化。如要向 Compose 表明應追蹤物件的狀態,該物件的類型需為 StateMutableStateState 類型不可變動,且只能讀取。MutableState 類型可變動,並允許讀取及寫入。

您已在先前的程式碼研究室的 Lemonade 應用程式Tip Time 應用程式中看過及使用 MutableState

如要建立可變動的變數 revenue,請使用 mutableStateOf 進行宣告。0 是其初始預設值。

var revenue = mutableStateOf(0)

這雖然足以讓 Compose 在收益值變更時觸發重組作業,但並不足以保留更新後的值。每次重新執行可組合函式時,都會將收益值重新初始化為 0 的初始預設值。

如要指示 Compose 在重組期間保留並重複使用這個值,則必須使用 remember API 宣告。

var revenue by remember { mutableStateOf(0) }

如果 revenue 的值有所變更,Compose 會為所有讀取這個值的可組合函式安排重組時間。

雖然 Compose 會在重組期間記住收益狀態,但不會在設定變更期間保留此狀態。為了讓 Compose 在設定變更期間保留狀態,您必須使用 rememberSaveable

如需其他練習與資訊,請參考「Compose 中的狀態簡介」程式碼研究室。

使用 rememberSaveable 在設定變更時儲存值

如果 Android 作業系統刪除並重新建立活動,您要使用 rememberSaveable 函式儲存所需的值。

如要在重組期間儲存值,您必須使用 remember。在重組「和」設定變更期間使用 rememberSaveable 來儲存值。

使用 rememberSaveable 儲存值可確保在還原活動時可用 (如需要)。

  1. MainActivity 中,將目前使用 remember 的 5 個變數群組更新為 rememberSaveable
var revenue by remember { mutableStateOf(0) }
...
var currentDessertImageId by remember {
    mutableStateOf(desserts[currentDessertIndex].imageId)
}
var revenue by rememberSaveable { mutableStateOf(0) }
...
var currentDessertImageId by rememberSaveable {
    mutableStateOf(desserts[currentDessertIndex].imageId)
}
  1. 編譯並執行應用程式。
  2. 按數次杯子蛋糕,但請注意,售出甜點和總收益不為零。
  3. 將裝置或模擬器旋轉至橫向模式。
  4. 請注意,在活動刪除並重新建立活動之後,甜點圖片、售出甜點和總收益都會還原為先前的值。

6. 解決方案程式碼

7. 摘要

活動生命週期

  • 活動生命週期是一組活動轉移的狀態。活動生命週期是從 Android 作業系統首次建立活動時開始,並在 OS 刪除活動時結束。
  • 使用者在不同活動之間及應用程式內外瀏覽時,每個活動會在活動生命週期的狀態之間切換。
  • 活動生命週期中的每個狀態都有相應的回呼方法,可在 Activity 類別中覆寫。生命週期方法的核心組合如下:onCreate()onRestart()onStart()onResume()onPause()onStop()onDestroy()
  • 如要新增在活動轉換為生命週期狀態時發生的行為,請覆寫狀態的回呼方法。
  • 如要在 Android Studio 中為類別新增架構覆寫方法,請選取「Code」>「Override Methods...」,或按下 Control+O 鍵。

使用記錄檔進行記錄

  • Android Logging API (尤其是 Log 類別),可讓您編寫在 Android Studio 的 Logcat 中顯示的簡短訊息。
  • 請使用 Log.d() 編寫偵錯訊息。這個方法使用兩個引數:記錄標記,通常是類別名稱,以及記錄訊息,此為簡短字串。
  • 使用 Android Studio 中的「Logcat」視窗檢視系統記錄,包括您編寫的訊息。

設定變更

  • 設定變更於裝置狀態改變時發生,因此基本上,使系統解決變更的最簡單方法就是刪除,然後重新建立活動。
  • 最常見的設定變更範例為,使用者將裝置從直向轉為橫向模式,或從橫向轉為直向模式時。當裝置語言變更或使用者外接硬體鍵盤時,也可能發生設定變更。
  • 發生設定變更時,Android 會叫用所有活動生命週期的關閉回呼。接著,Android 會從頭重新啟動活動,並執行所有生命週期啟動回呼。
  • Android 因設定變更而關閉應用程式時,Android 會以 onCreate() 重新啟動活動。
  • 如要儲存需要在設定變更後繼續有效的值,需以 rememberSaveable 宣告其變數。

瞭解詳情