Android Compose UI 狀態管理 (State, MutableState, remember)
在宣告式 UI 中,UI 是狀態 (State) 的函數。
UI = f(State)
如果狀態不改變,UI 就不會改變。因此,學習 Compose 的關鍵就在於學習如何管理狀態。
什麼是 State?
在 Compose 中,State<T> 是一個持有值並能通知 UI 更新的介面。最常用的是 MutableState<T>。
當 MutableState 的值改變時,讀取該值的 Composable 函式會自動觸發 Recomposition。
remember 的作用
Composable 函式可能會被頻繁地重新執行 (Recomposition)。如果你直接在函式裡定義變數:
@Composable
fun Counter() {
// ❌ 錯誤:每次重組時,count 都會被重置為 0
var count = mutableStateOf(0)
Button(onClick = { count.value++ }) {
Text("Count: ${count.value}")
}
}
你需要使用 remember 來告訴 Compose:「請幫我在記憶體中記住這個值,即使發生重組也不要遺忘」。
@Composable
fun Counter() {
// ✅ 正確:使用 remember 保存狀態
val count = remember { mutableStateOf(0) }
Button(onClick = { count.value++ }) {
Text("Count: ${count.value}")
}
}
Property Delegate (屬性委派)
為了讓語法更簡潔,我們通常使用 Kotlin 的 by 關鍵字:
// 需要 import androidx.compose.runtime.*
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count") // 直接使用 Int,不需要 .value
}
rememberSaveable (跨越組態變更)
remember 只能在重組 (Recomposition) 期間保存狀態。但是當發生 組態變更 (Configuration Change),例如螢幕旋轉時,Activity 會被重建,remember 的值會遺失。
如果你希望狀態在螢幕旋轉後依然保留,請使用 rememberSaveable。
var count by rememberSaveable { mutableStateOf(0) }
它會自動將資料儲存到 Bundle 中,並在重建後恢復。注意:儲存的資料必須是可序列化的 (Serializable/Parcelable) 或是基本型別。
Stateless vs Stateful
- Stateful Composable:內部持有並管理自己的狀態(使用
remember)。優點是好用,缺點是難以測試與重用。 - Stateless Composable:不持有狀態,狀態由外部參數傳入,事件由外部 Lambda 處理。優點是易於測試與重用。
最佳實踐:State Hoisting (狀態提升)。 盡量讓底層的 Composable 保持 Stateless,將狀態「提升」到上層的 Composable 或 ViewModel 中管理。
小結
- State 驅動 UI 更新。
- remember 防止重組時狀態遺失。
- rememberSaveable 防止旋轉螢幕時狀態遺失。