視狀態提升至的位置和所需的邏輯而定 可以使用不同的 API 來儲存及還原 UI 狀態。每個應用程式都會使用 以達到這個目的。
任何 Android 應用程式都可能會因為活動或程序而遺失 UI 狀態 重新建立。以下是可能引發這類情況的事件:
,瞭解如何調查及移除這項存取權。對正面使用者來說,在事件發生後保留狀態至關重要 無須專人管理而您該選擇保留哪些狀態,則視應用程式的不重複使用者人數而定 流程最佳做法是至少保存使用者輸入內容 導覽相關狀態。舉例來說, 清單、使用者想進一步瞭解的項目 ID、進行中 使用者偏好設定選項,或在文字欄位中輸入的內容
本頁總結了可用 API 儲存 UI 狀態的 API,具體情況取決於 狀態就會提升至需要狀態的邏輯
UI 邏輯
如果狀態是在 UI 中提升 (無論是在可組合函式中或純狀態),
範圍限定為組合的狀態容器類別
rememberSaveable
用於在重新建立活動和程序後保留狀態。
在以下程式碼片段中,rememberSaveable
的作用是儲存單一布林值
UI 元素狀態:
@Composable fun ChatBubble( message: Message ) { var showDetails by rememberSaveable { mutableStateOf(false) } ClickableText( text = AnnotatedString(message.content), onClick = { showDetails = !showDetails } ) if (showDetails) { Text(message.timestamp) } }
showDetails
是一個布林值變數,可在即時通訊泡泡處於收合狀態時儲存
或已展開的情況
rememberSaveable
會透過 Bundle
將 UI 元素狀態儲存在 Bundle
中
儲存的執行個體狀態機制
基本類型可以自動儲存在套件中。如果您所在的州/省
以非原始的類型 (例如資料類別) 保留
不同的儲存機制,例如使用 Parcelize
註解。
使用 listSaver
和 mapSaver
等 Compose API,或實作
自訂 Saver 類別,擴充 Compose 執行階段 Saver
類別。請參閱方式
儲存狀態說明文件,進一步瞭解這些方法。
在以下程式碼片段中,rememberLazyListState
Compose
API 會儲存 LazyListState
,其中包含
LazyColumn
或 LazyRow
,使用 rememberSaveable
。該公式採用
LazyListState.Saver
是自訂儲存工具,可以
儲存並還原捲動狀態重新建立活動或程序後 (
例如,在設定變更 (例如變更裝置螢幕方向) 後,
因此會保留捲動狀態
@Composable fun rememberLazyListState( initialFirstVisibleItemIndex: Int = 0, initialFirstVisibleItemScrollOffset: Int = 0 ): LazyListState { return rememberSaveable(saver = LazyListState.Saver) { LazyListState( initialFirstVisibleItemIndex, initialFirstVisibleItemScrollOffset ) } }
最佳做法
rememberSaveable
使用 Bundle
儲存 UI 狀態,由該狀態共用
其他也會寫入其資料的 API,例如onSaveInstanceState()
您的活動。不過,這個 Bundle
的大小有限,且會儲存大型
物件可能會在執行階段中發生 TransactionTooLarge
例外狀況。這個
這在單個 Activity
應用程式中可能特別有問題
目前已在應用程式中使用 Bundle
。
為了避免這種異常終止情形,請勿儲存大型物件或 組合中的物件清單。
請改為儲存所需的最低狀態 (例如 ID 或鍵),並用於 委派將還原更複雜的 UI 狀態給其他機制,例如永久性機制 如果 30 天內讀取資料不到一次 建議使用 Nearline Storage
請根據應用程式的用途,選擇適合的選項 使用者期望應用程式能正常運作
驗證狀態還原
您可以使用 rememberSaveable
,確認儲存狀態是否位於
當活動或程序發生時,Compose 元素會正確還原
重新建立有些 API 就是為此設計
StateRestorationTester
。請參閱測試說明文件,
瞭解詳情。
商業邏輯
如果 UI 元素狀態因ViewModel
為了讓商業邏輯所需,您可以使用 ViewModel
的 API。
在 Android 應用程式中使用 ViewModel
的主要優點之一,就是
免費處理設定變更如果有設定
系統就會刪除並重新建立活動,UI 狀態也提升為
ViewModel
會保存在記憶體中。重新建立完畢後,舊的 ViewModel
附加至新的活動例項。
不過,ViewModel
例項無法在系統終止程序後繼續存留。
如果想保留 UI 狀態,請使用 [儲存狀態] 模組
ViewModel,內含 SavedStateHandle
API。
最佳做法
SavedStateHandle
也會使用 Bundle
機制儲存 UI 狀態,因此
應該只用來儲存簡單的 UI 元素狀態。
畫面 UI 狀態,此狀態是套用業務規則並存取
應用程式層中,請勿使用 UI 以外的其他層
SavedStateHandle
,因為可能相當複雜且大小不容小覷。別擔心!您可以使用
不同機制 (例如儲存複雜或大型資料)
如果 30 天內讀取資料不到一次
建議使用 Nearline Storage重新建立程序後,系統會使用
還原的暫時性狀態,儲存在 SavedStateHandle
中 (如有),以及
系統會再次從資料層產生畫面 UI 狀態。
SavedStateHandle
API
SavedStateHandle
有各種用來儲存 UI 元素狀態的 API,大部分
值得注意的是:
撰寫 State |
saveable() |
---|---|
StateFlow |
getStateFlow() |
撰寫 State
使用 SavedStateHandle
的 saveable
API 讀取及寫入 UI 元素
狀態變為 MutableState
,因此在活動和程序重建後仍然有效
僅需少量程式碼設定
saveable
API 可直接支援基本類型,並會接收
stateSaver
參數以使用自訂 Saver,就像 rememberSaveable()
一樣。
在以下程式碼片段中,message
會將使用者輸入類型儲存至
TextField
:
class ConversationViewModel( savedStateHandle: SavedStateHandle ) : ViewModel() { var message by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } private set fun update(newMessage: TextFieldValue) { message = newMessage } /*...*/ } val viewModel = ConversationViewModel(SavedStateHandle()) @Composable fun UserInput(/*...*/) { TextField( value = viewModel.message, onValueChange = { viewModel.update(it) } ) }
詳情請參閱 SavedStateHandle
說明文件
透過 saveable
API 部署該物件
StateFlow
使用 getStateFlow()
儲存 UI 元素狀態,並將其做為資料流使用
SavedStateHandle
。已讀取 StateFlow
,且 API 會要求您指定金鑰,這樣您就能將流程
發出新值。設定金鑰後,您就能擷取 StateFlow
並收集最新的值
在以下程式碼片段中,savedFilterType
是 StateFlow
變數,
儲存套用至即時通訊頻道清單的篩選器類型:
private const val CHANNEL_FILTER_SAVED_STATE_KEY = "ChannelFilterKey" class ChannelViewModel( channelsRepository: ChannelsRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val savedFilterType: StateFlow<ChannelsFilterType> = savedStateHandle.getStateFlow( key = CHANNEL_FILTER_SAVED_STATE_KEY, initialValue = ChannelsFilterType.ALL_CHANNELS ) private val filteredChannels: Flow<List<Channel>> = combine(channelsRepository.getAll(), savedFilterType) { channels, type -> filter(channels, type) }.onStart { emit(emptyList()) } fun setFiltering(requestType: ChannelsFilterType) { savedStateHandle[CHANNEL_FILTER_SAVED_STATE_KEY] = requestType } /*...*/ } enum class ChannelsFilterType { ALL_CHANNELS, RECENT_CHANNELS, ARCHIVED_CHANNELS }
每當使用者選取新的篩選器類型,就會呼叫 setFiltering
。這個
在 SavedStateHandle
中使用鍵儲存新值
_CHANNEL_FILTER_SAVED_STATE_KEY_
。savedFilterType
是會發出
最新的值。filteredChannels
已訂閱以下資料流:
執行頻道篩選條件
請參閱SavedStateHandle
說明文件,進一步瞭解
getStateFlow()
API。
摘要
下表歸納了本節介紹的 API 及使用時機 逐一儲存 UI 狀態:
活動 | UI 邏輯 | ViewModel 中的商業邏輯 |
---|---|---|
設定變更 | rememberSaveable |
自動 |
系統終止程序 | rememberSaveable |
SavedStateHandle |
要使用哪一個 API,取決於狀態儲存的位置和其邏輯
而負責任的 AI 技術做法
有助於達成這項目標對於 UI 邏輯中使用的狀態,請使用 rememberSaveable
;適用對象
商業邏輯中使用的狀態 (如果您的保存在 ViewModel
中)。
使用 SavedStateHandle
儲存。
您應使用 bundle API (rememberSaveable
和 SavedStateHandle
) 執行
儲存少量 UI 狀態這項資料是還原所需最低限度的資料
UI 和其他儲存機制適用對象
舉例來說,如果您將使用者先前查看的設定檔 ID 儲存在套件中,
您可以從資料層擷取商家檔案詳情等大量資料。
如要進一步瞭解各種儲存 UI 狀態的方式,請參閱一般 儲存 UI 狀態說明文件和 架構指南
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 在何種情況下提升狀態
- 狀態和 Jetpack Compose
- 清單和格線