此系列文章是以我的業餘專案: Kimoji 作為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!
立馬下載
延續昨天的文章,今天我們來把 UI 狀態 (也就是日記清單) 搬到 ViewModel
,然後開始抽出事務邏輯。
DiaryViewModel.kt
,並定義 ViewModel
class。把我們的「資料來源」getDiaries()
移到 DiaryViewModel
。
定義 _diaries
內部變數,透過前兩天文章介紹的的方法,使用 toMutableStateList
來指定初值,然後曝露 diaries
日記清單,讓它的值只能透過 ViewModel
來變更。
我們使用 List
內建的 remove
函式,來實作簡單的刪除功能。
import androidx.compose.runtime.toMutableStateList
import androidx.lifecycle.ViewModel
class DiaryViewModel : ViewModel() {
private val _diaries = getDiaries().toMutableStateList()
val diaries: List<Diary>
get() = _diaries
fun remove(diary: Diary) {
_diaries.remove(diary)
}
}
private fun getDiaries() = List(30) { i -> Diary(i, "Day # $i") }
viewModel()
函式,從任何 composable 來存取這個 ViewModel
。如果要使用這個函式,開啟 app/build.gradle
檔案並加入以下 library,然後在 Android Studio sync dependencies:
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1")
DiaryScreen
。新增 diaryViewModel
當做 DiaryScreen
composable 的參數,並呼叫 viewModel()
來初始化 ViewModel
instance。這樣的介面設計,有助於在測試這個 composable 時抽換 ViewModel
,並可在需要時 hoist state holder。接著,我們將「日記清單」和「刪除函式」傳給 Journal
composable,並移除我們之前定義的 onDelete
lambda 函式。import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun DiaryScreen(
modifier: Modifier = Modifier,
diaryViewModel: DiaryViewModel = viewModel()
) {
Column(modifier = modifier) {
StatefulCounter()
Journal(
diaries = diaryViewModel.diaries,
onDelete = { diary -> diaryViewModel.remove(diary) }
)
}
}
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」代表它比較靠近從
Activity
、Fragment
或 Navigation graph destination 呼叫的 root composable。ViewModel
不應向下傳遞給其他 composable,而應該只往下傳遞需要的資料,以及執行必要邏輯的函式。如果想深入瞭解,請參閱 ViewModel 和 state holder,以及官方的 Compose and other libraries 說明文件。
此系列文章是以我的業餘專案:Kimoji 為範例。
Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!
立馬下載
Reference: https://developer.android.com/codelabs/jetpack-compose-state