將 data 和 event 遷移到 ViewModel

Kimoji:以 Jetpack Compose 實作一款「心情日記」應用 [23]

John Lu
5 min readSep 26, 2022

此系列文章是以我的業餘專案: Kimoji 為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!
📥 立馬下載 | | | 🎟️ 限免兌換碼

延續昨天的文章,今天我們來把 UI 狀態 (也就是日記清單) 搬到 ViewModel,然後開始抽出事務邏輯。

  1. 建立檔案 DiaryViewModel.kt,並定義 ViewModel class。

把「資料來源」getDiaries() 移到 DiaryViewModel

定義 _diaries 內部變數,透過前兩天文章介紹的方法,使用 toMutableStateList來指定初值,然後曝露 diaries 日記清單,讓它的值只能透過 ViewModel 來變更。

我們使用 List內建的 remove 函式,來實作簡單的刪除功能。

2. 我們可以藉由呼叫 viewModel() 函式,從任何 composable 來存取這個 ViewModel

如果要使用這個函式,開啟 app/build.gradle 檔案並加入以下 library,然後在 Android Studio sync dependencies:

3. 開啟 DiaryScreen。新增 diaryViewModel當做DiaryScreen composable 的參數,並呼叫 viewModel()來初始化 ViewModel instance。這樣的介面設計,有助於在測試這個 composable 時抽換 ViewModel,並可在需要時 hoist state holder。接著,我們將「日記清單」和「刪除函式」傳給 Journal composable,並移除我們之前定義的 onDelete lambda 函式。

viewModel() 會傳回現有的 ViewModel 或在指定 scope 內建立新的 ViewModel。只要 scope 還存續著,系統就會保留 ViewModel 的 instance。例如,如果在 Activity 中使用 composable,viewModel() 會傳回相同的 instance,直到 Activity finish 或 kill process 為止。

我們已經把畫面上一部分狀態和事務邏輯與 ViewModel 整合。由於狀態會保留在 Composition 之外,並由 ViewModel 儲存,因此對「日記清單」的變動就可以撐過 configuration changes 了。

ViewModel 無法在所有情況下自動維持 app 的狀態 (例如系統觸發的 process death)。如果想詳細瞭解如何維持 app 的 UI 狀態,可以參閱說明文件。

ViewModel 適合被引用在畫面層級的 composable,「畫面層級的 composable」代表它較為靠近從 ActivityFragment或 Navigation graph destination 呼叫的 root composable。ViewModel 不應向下傳遞給其他 composable,而應該只往下傳遞需要的資料,以及執行必要邏輯的函式。

如果想深入瞭解,請參閱 ViewModel 和 state holder,以及官方的 Compose and other libraries 說明文件。

此系列文章是以我的業餘專案: Kimoji 為範例

Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!
📥 立馬下載 | | | 🎟️ 限免兌換碼

--

--

John Lu

AI Engineer. Deeply motivated by challenges and tends to be excited by breaking conventional ways of thinking and doing. He builds fun and creative apps.