今天大概會聊到的範圍
- viewModel in Compose
今天的主題很單純:如果專案中有使用到 Compose 又有用到 Android Architecture Component 的 ViewModel 與 LiveData 的話,要怎麼讓資料在 Compose 內外傳遞呢?
首先,先建立今天的主角 ViewModel
class FooViewModel : ViewModel() {
val buzzLiveData: LiveData<List<String>>
get() = _buzzLiveData
private val _buzzLiveData = MutableLiveData<List<String>>(emptyList())
fun addData(param: String) {
_buzzLiveData.value = _buzzLiveData.value?.let { it + listOf(param) }
}
}
ViewModel 可以在 Activity 層建立,方法就和一般的 ViewModel 一樣:
class BarActivity : ComponentActivity() {
private val vm: FooViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
FooComposable(vm) // <--
}
}
}
@Composable
fun FooComposable(vm: FooViewModel) { ... }
在 Activity 建立 ViewModel 後,可以將其當成一般的參數傳入 Composable。
@Composable
fun FooComposable(model: FooViewModel) {
val data by model.buzzLiveData.observeAsState(initial = emptyList()) // <--- 1
Column {
LazyColumn {
items(data) { // <--- 2
Text(it)
}
}
Button({ model.addData("one") }) { // <--- 3
Text("add data")
}
}
}
observeAsState
需要implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07"
observeAsState
來將 LiveData 轉換成 State注意!呼叫 ViewModel function 的部分若是放在 composable function 中,會變成 side-effect 。若真的要執行需要特別處理 ( 上一篇的主題 )
Button 的 onClick callback 不是 composable function
@Composable
fun FooComposable(model: FooViewModel = viewModel()) { ... }
若不一定要外部的使用者提供 ViewModel,也可以透過 viewModel()
來現場建立一個 viewModel。
observeAsState
Under the hoodobserveAsState
到底怎麼把 LiveData 轉成 State 的呢?我們可以來研究一下 observeAsState
的實作:
@Composable
fun <R, T : R> LiveData<T>.observeAsState(initial: R): State<R> {
val lifecycleOwner = LocalLifecycleOwner.current // < --- 1
val state = remember { mutableStateOf(initial) } // < --- 2
DisposableEffect(this, lifecycleOwner) { // < --- 5
val observer = Observer<T> { state.value = it } // < --- 3
observe(lifecycleOwner, observer)
onDispose { removeObserver(observer) } // < --- 6
}
return state // < --- 4
}
LocalLifecycleOwner
可以取得目前 Composable 所在 scope 的 LifecycleOwner
remember { mutableStateOf() }
將資料存放起來LiveData.observe
去觀察 LiveData 的資料,若有改動就將資料同步到 stateLiveData
or LifecycleOwner
有異動的時候能重新做 observe ,且除此之外不要做異動。使用之前提到過的 DisposableEffect
onDispose
時,將 observer 回收想不到 ViewModel 和 LiveData 在 Compose 中的使用其實非常的簡單。在 LiveData 背後,又剛好是使用到之前所研究的 Side Effect API,感覺整個技術都串起來了!
Reference: