iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0

https://ithelp.ithome.com.tw/upload/images/20220912/20151958IFjRs0xIZ4.png Medium 好讀版

此系列文章是以我的業餘專案: Kimoji 作為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!

https://ithelp.ithome.com.tw/upload/images/20220907/20151958vXuPLv4aki.png 立馬下載

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

  1. 建立檔案 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") }
  1. 我們可以藉由呼叫 viewModel() 函式,從任何 composable 來存取這個 ViewModel

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

implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1")
  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」代表它比較靠近從 ActivityFragment 或 Navigation graph destination 呼叫的 root composable。ViewModel 不應向下傳遞給其他 composable,而應該只往下傳遞需要的資料,以及執行必要邏輯的函式。

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

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

Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!

https://ithelp.ithome.com.tw/upload/images/20220907/20151958vXuPLv4aki.png 立馬下載

Reference: https://developer.android.com/codelabs/jetpack-compose-state


上一篇
ViewModel 中的狀態
下一篇
Compose 實作清單多選
系列文
Kimoji:以 Jetpack Compose 實作一款「心情日記」應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言