將 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
John Lu

Written by 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.