多項 Android 系統作業可能會影響片段的狀態。為確保系統會儲存使用者的狀態,Android 架構會自動儲存並還原片段和返回堆疊。因此,您需要 確保系統會儲存及還原片段中的所有資料。
下表概略說明了導致片段遺失狀態的作業,以及各種類型的狀態是否會在這些變更過程中持續存在。表格中提到了以下狀態類型:
- 變數:片段中的本機變數。
- 查看狀態:片段中由一或多個檢視畫面擁有的任何資料。
- SavedState:應儲存在
onSaveInstanceState()
中的該片段執行個體固有的資料。 - NonConfig:從外部來源 (如伺服器或本機存放區) 提取的資料,或在提交後傳送至伺服器的使用者建立資料。
變數通常被視為與 SavedState 相同,但下表對二者進行了區分,以便說明各種作業對每個狀態的影響。
作業 | 變數 | 查看狀態 | SavedState | NonConfig |
---|---|---|---|---|
已新增至返回堆疊 | ✓ | ✓ | x | ✓ |
設定變更 | x | ✓ | ✓ | ✓ |
程序終止/重新建立 | x | ✓ | ✓ | ✓* |
已移除未新增至返回堆疊 | x | x | x | x |
主機結束 | x | x | x | x |
* 使用 ViewModel 的已儲存狀態模組,可在程序終止過程中保留 NonConfig 狀態。
表 1:各種片段破壞性作業及其對不同狀態類型的影響。
我們來看看具體範例。假設螢幕產生隨機字串,以 TextView
顯示該字串,並在將其傳送給朋友之前提供字串編輯選項:
在此範例中,假設使用者按下編輯按鈕後,應用程式會顯示可供編輯訊息的 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
在程序終止和重新建立期間維持簡單狀態。
其他資源
如要進一步瞭解如何管理片段狀態,請參閱下列其他資源。
程式碼研究室
- 生命週期感知元件程式碼研究室