思路
对 viewmodel 中 livedata 的监听也是返回一个 state.
但这个 state 是不能像 compose 内的 state 直接修改的。要修改,需要调用 viewmodel 中的函数来间接修改。
尝试过的方案
- 方案一(失败):ViewModel 中定义 mutableStateOf, Composable 中定义 mutableStateOf。mutableStateOf 看起来是初始化那一刻用的啥值,就是啥值,无法自动更新。
- 方案二(可行):ViewModel 中定义 MutableLiveData,Composable 中使用 observeAsState 监听 LiveData 的变化。
示例代码
ViewModel 中:
var currentItem = MutableLiveData<Item>(defaultItem)
fun getItemById(id: String) {
viewModelScope.launch(Dispatchers.IO) {
currentItem.postValue(repository.getItemById(id))
}
}
val setCurrentItem: (Item) -> Unit = { item ->
currentItem.value = item
}
setCurrentItem 是为了模仿 mutableStateOf 返回的 setItem 那种写法。
Composable 中:
val item by itemViewModel.currentItem.observeAsState(defaultItem)
if (id != "new") {
itemViewModel.getItemById(id!!)
}
这种用了个笨办法,就是判断如果是在 detail 页,就手动调用 viewModel 中的 getItemById 来更新 LiveData 的值。
observeAsState
observeAsState 用于监听 LiveData 的值,并返回一个 State,用于更新 Composable。
observeAsState 的两种用法:
- 有默认值
- 无默认值
import androidx.compose.material.Text
import androidx.compose.runtime.livedata.observeAsState
val value: String? by liveData.observeAsState()
Text("Value is $value")
val value: String by liveData.observeAsState("initial")
Text("Value is $value")
observeAsState 返回的 State 是不可变更的
@Composable
fun <T : Any?> LiveData<T>.observeAsState(): @Composable State<T?>
mutableStateOf
而 mutableStateOf 返回的是 MutableState,可以修改其值。
fun <T : Any?> mutableStateOf(
value: T,
policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T>
例如:
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
val (count, setCount) = remember { mutableStateOf(0) }
Text(text = "You clicked $count times")
Button(onClick = { setCount(count + 1) }) {
Text("Click me")
}
MutableLiveData
ViewModel 定义 MutableLiveData 来实现可变更的 LiveData。 这样就能在 Composable 中通过 ViewModel 对外开发的函数来修改 LiveData。
class HelloViewModel : ViewModel() {
// LiveData holds state which is observed by the UI
// (state flows down from ViewModel)
private val _name = MutableLiveData("")
val name: LiveData<String> = _name
// onNameChange is an event we're defining that the UI can invoke
// (events flow up from UI)
fun onNameChange(newName: String) {
_name.value = newName
}
}
修改 MutableLiveData 的值,需要使用 postValue 或者 setValue,区别参考:
Difference of setValue() & postValue() in MutableLiveData
- setValue 需要在主线程中调用
- postValue 需要在后台线程中调用
- 但是还有使用 .value 的情况,看起来跟 setValue 是一样的
如果数据源来自网络呢
上面是使用本地 Room 的存储方案,如果使用网络数据,可以参考
https://github.com/ellisonchan/ComposeMovie
参考
https://stackoverflow.com/questions/61619408/livedata-in-combination-with-jetpack-compose
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式