使用片段來儲存狀態

多項 Android 系統作業可能會影響片段的狀態。為確保系統會儲存使用者的狀態,Android 架構會自動儲存並還原片段和返回堆疊。因此,您需要確保能夠儲存及還原片段中的所有資料。

下表概略說明了導致片段遺失狀態的作業,以及各種類型的狀態是否會在這些變更過程中持續存在。表格中提到了以下狀態類型:

  • 變數:片段中的本機變數。
  • 查看狀態:片段中一個或多個檢視畫面擁有的資料。
  • SavedState:應儲存在 onSaveInstanceState() 中的該片段執行個體固有的資料。
  • NonConfig:從外部來源 (如伺服器或本機存放區) 提取的資料,或在提交後傳送至伺服器的使用者建立資料。

變數通常被視為與 SavedState 相同,但下表對二者進行了區分,以便說明各種作業對每個狀態的影響。

作業 變數 查看狀態 SavedState NonConfig
已新增至返回堆疊 x
設定變更 x
程序終止/重新建立 x ✓*
已移除未新增至返回堆疊 x x x x
主機結束 x x x x

* 使用 ViewModel 的已儲存狀態模組,可在程序終止過程中保留 NonConfig 狀態。

表 1:各種片段破壞性作業及其對不同狀態類型的影響。

我們來看看具體範例。假設螢幕產生隨機字串,以 TextView 顯示該字串,並在將其傳送給朋友之前提供字串編輯選項:

示範各種狀態類型的隨機文字產生器應用程式
圖 1.示範各種狀態類型的隨機文字產生器應用程式。

在此範例中,假設使用者按下編輯按鈕後,應用程式會顯示可供編輯訊息的 EditText 檢視區塊。如果使用者點選「CANCEL」,系統就應該清除 EditText 檢視區塊,並將其瀏覽權限設為 View.GONE。這類畫面可能需要管理四項資料,以確保流暢的使用體驗:

資料 類型 狀態類型 說明
seed Long NonConfig 用於隨機產生新善行的種子。會在建立 ViewModel 時產生。
randomGoodDeed String SavedState + 變數 會在首次建立片段時產生。系統會儲存 randomGoodDeed,以確保在程序終止和重新建立後,使用者仍可看到相同的隨機善行。
isEditing Boolean SavedState + 變數 當使用者開始編輯時,布林值標記設為 true。系統會儲存 isEditing,確保重建片段後,畫面仍會顯示編輯部分。
已編輯的文字 Editable 查看狀態 (擁有者:EditText) EditText 檢視表中的已編輯文字。EditText 檢視表會儲存這段文字,確保使用者不會遺失正在進行的變更。

表 2:隨機文字產生器應用程式必須管理的狀態。

以下章節說明如何透過破壞性作業妥善管理資料狀態。

查看狀態

檢視表應負責管理自己的狀態。例如,如果檢視表接受使用者輸入內容,檢視表有責任儲存和還原該輸入內容,以便處理設定變更。Android 架構提供的每個檢視區塊都有專屬的 onSaveInstanceState()onRestoreInstanceState() 實作方式,因此您無需管理片段中的檢視區塊狀態。

例如,在前一個情境中,編輯後的字串會保存在 EditText 中。EditText 知道其顯示的文字值,以及其他詳細資料,例如任何選取文字的開頭和結尾。

檢視表必須擁有 ID 才能保留其狀態。這個 ID 在片段及其檢視區塊階層中不得重複。沒有 ID 的檢視表無法保留其狀態。

<EditText
    android:id="@+id/good_deed_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

如表 1 所述,檢視表會在不移除片段或破壞主機的所有作業期間儲存並還原其 ViewState

SavedState

您的片段負責管理少量的動態狀態,這些動態狀態對於片段的運作方式至關重要。您可以使用 Fragment.onSaveInstanceState(Bundle) 保留可輕易序列化的資料。與 Activity.onSaveInstanceState(Bundle) 類似,在設定變更或程序終止並重建之後,您放在套裝組合中的資料將會保留,並能在片段的 onCreate(Bundle)onCreateView(LayoutInflater, ViewGroup, Bundle)onViewCreated(View, Bundle) 方法中使用。

延續上例,randomGoodDeed 是對使用者顯示的行為,isEditing 標記則用於確定片段是否會顯示 EditText。此儲存狀態應使用 onSaveInstanceState(Bundle) 持續保留,如以下範例所示:

Kotlin

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putBoolean(IS_EDITING_KEY, isEditing)
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed)
}

Java

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(IS_EDITING_KEY, isEditing);
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed);
}

如要還原 onCreate(Bundle) 中的狀態,請從套裝組合中擷取已儲存的值:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false)
    randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY)
            ?: viewModel.generateRandomGoodDeed()
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false);
        randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY);
    } else {
        randomGoodDeed = viewModel.generateRandomGoodDeed();
    }
}

如表 1 所述,將片段放在返回堆疊上時,系統會保留變數。將這些變數視為已儲存狀態,可確保其在所有破壞作業期間持續保留。

NonConfig

NonConfig 資料應放在片段以外的位置,例如放在 ViewModel 中。在之前的範例中,seed (我們的 NonConfig 狀態) 會在 ViewModel 中產生。用來維持狀態的邏輯為 ViewModel 所有。

Kotlin

public class RandomGoodDeedViewModel : ViewModel() {
    private val seed = ... // Generate the seed

    private fun generateRandomGoodDeed(): String {
        val goodDeed = ... // Generate a random good deed using the seed
        return goodDeed
    }
}

Java

public class RandomGoodDeedViewModel extends ViewModel {
    private Long seed = ... // Generate the seed

    private String generateRandomGoodDeed() {
        String goodDeed = ... // Generate a random good deed using the seed
        return goodDeed;
    }
}

ViewModel 類別本身允許資料在變更設定 (例如螢幕旋轉) 期間持續存在,當將片段置於返回堆疊後,資料將保留在記憶體中。程序終止並重建後,系統會重新建立 ViewModel 並產生新的 seed。將 SavedState 模組新增至 ViewModel,可讓 ViewModel 在程序終止和重新建立期間維持簡單狀態。

其他資源

如要進一步瞭解如何管理片段狀態,請參閱下列其他資源。

程式碼研究室

指南