Jetpack Compose 狀態管理完全指南:精通 remember 和 mutableStateOf

  • Compose 中的狀態是響應式的,這表示可觀察物件的任何變更都會自動觸發介面的重新組合。
  • remember 和 mutableStateOf 的組合可以讓值在重繪週期中保留下來,而 rememberSaveable 可以保護資料免受螢幕旋轉的影響。
  • 狀態提升模式是建立可重複使用元件和將業務邏輯與表現層解耦的基礎。
  • 透過與 ViewModel 整合以及使用單向資料流,確保了可擴展且易於測試的架構。

Jetpack Compose 中的狀態管理

如果你熟悉傳統的 Android 視圖,你可能已經習慣了處理 XML ID 並呼叫諸如 `setText` 之類的方法來更新畫面。但在 Jetpack Compose 的世界裡,方法截然不同:使用者介面是狀態的函數。這意味著我們無需手動將變更推送至視圖;相反,我們根據當前資料定義應用程式的外觀,然後讓框架完成其餘的工作。

剛開始可能需要一些練習才能掌握這種聲明式工作流程,但一旦你熟悉了,你會發現它簡潔得多。關鍵在於理解狀態是指任何會隨時間變化的值,從簡單的點讚計數器到複雜的房間資料庫,而使用者介面會根據這些變化做出相應的反應。

響應式的核心:mutableStateOf

要告訴 Compose 需要重繪螢幕的一部分,僅僅使用標準的Kotlin變數是不夠的。我們需要一些系統可以「監控」的東西。這就是`mutableStateOf` 的作用所在,它創造了一個可觀察的容器。當這個容器中的值發生變化時,Compose 會將所有讀取該值的函數標記為“無效”,並啟動重繪。

有幾種方法可以聲明這些狀態,使程式碼更簡潔。我們可以使用帶有 `by` 運算子的屬性委託語法,這樣就可以像處理普通變數一樣處理狀態,而無需每次都寫 `.value`。為了讓這種方法生效,請不要忘記從 Compose 執行時間套件中匯入 `getValue` 和 `setValue`,因為有時 IDE 不會自動包含它們。

使用 Compose Multiplatform 在 Kotlin Multiplatform 中設計共享 UI 狀態架構
相關文章:
使用 Compose Multiplatform 在 Kotlin Multiplatform 中設計共享 UI 狀態架構

作曲記憶:記憶的作用

初學者常犯的一個錯誤是在可組合物件中聲明狀態時沒有對其進行保護。由於重新組合本質上是重新執行函數,因此每次迭代中普通變數都會被重置。例如,如果你有一個文字字段,你會發現它不會寫入任何內容,因為每次按鍵後幾毫秒變數就會再次變成空。

為了解決這個問題,我們使用了`remember`,它會在元件首次執行時將值儲存在組合中,並在後續執行中檢索它。這就像告訴 Compose:「嘿,保存這些數據,即使需要重繪組件也不要丟棄它。」然而,`remember` 有一個限制:如果旋轉移動設備或 Activity 被銷毀,數據就會丟失。針對這些情況,解決方案是使用`rememberSaveable`,它會將資訊保存在一個 Bundle 中,從而使狀態能夠在配置變更後仍然有效。

如果您需要儲存無法直接放入 Bundle 的複雜對象,您可以選擇以下幾種方法。您可以使用`@Parcelize` 註解使資料類可進行 Parcel 處理;或者,如果您希望擁有更多控制權,可以實現 `mapSaver` 或 `listSaver` 來精確定義物件如何轉換為可存儲數據,以及資料如何從可儲存資料轉換為 MapSaver。

國家吊掛和再利用

當一個元件管理自身狀態時,我們稱之為有狀態元件。對於非常簡單的場景來說,這沒有問題,但這會使組件難以測試且靈活性降低。解決方案是狀態提升,即將狀態轉移到父元件。這樣,子元件就變成了無狀態元件,只負責顯示被要求的內容以及通知使用者狀態變更。

標準模式是用兩個參數取代狀態變數:一個參數用於儲存當前值,另一個參數是用於處理事件的 lambda 函數(例如 onValueChange)。這樣就創建了一個單向資料流,狀態值下降,事件值上升,從而避免了多個資料來源,並大幅減少了同步錯誤。

高階管理:效果、流程和視圖模型

隨著應用程式規模的成長,將所有邏輯都放在可組合物件中無異於自找麻煩。理想情況下,應該將這些邏輯委託給狀態容器,例如 ViewModel。 Compose與 LiveData 和 Flow 完美整合。例如,您可以使用`collectAsStateWithLifecycle`有效率地收集 Flow ,確保應用程式在螢幕不可見時不會消耗電池或資源。

為了處理副作用,Compose 提供了一些專門的工具。 LaunchedEffect允許你啟動協程,這些協程會在元件移出螢幕時自動取消;而 DisposableEffect 則非常適合清理任務。如果你有一個依賴其他狀態的值,那麼 derivedStateOf 就是你的最佳選擇,因為它可以防止在依賴項實際上沒有改變的情況下,每次重新組合時都執行耗時的計算。

優化與效能

編寫程式碼固然重要,但優化同樣關鍵。穩定性是關鍵所在。使用具有 `@Immutable` 註解的不可變類型,可以幫助 Compose 編譯器識別物件未發生改變,從而避免重新組合某些元件,進而提升速度。

對於長列表,使用 LazyColumn 或 LazyRow 至關重要,它們只會渲染當前可見的內容。此外,建議盡可能在元件樹的底層讀取狀態,這樣當狀態改變時,只會使受影響的一小部分 UI 失效,而不是整個螢幕,從而避免使用者體驗卡頓。

Jetpack Compose 中的 XML 視圖
相關文章:
使用動態函數模組和 Compose 在 Android 中實現微前端

從使用 `remember` 管理本機記憶體到實現單向流的 MVVM,整個架構讓 Android 開發更具可預測性。透過將業務邏輯分離到 ViewModel 中,並保持介面元件的純淨性和響應式,我們實現了可擴展、易於維護,最重要的是,能夠提供流暢導航且無狀態錯誤的應用程式。分享此訊息,讓更多用戶了解它。


沒有 Google 帳號的 Google Play 商店
它可能會讓你感興趣:
如何在沒有Google帳戶的情況下從Play商店下載應用
在 Google 中將其新增為首選來源