Jetpack Compose 使用 MutableLiveData 及 observeAsState 实现详情页的数据查询

发布时间: 2021-09-18 11:20:46 作者: 大象笔记

思路

对 viewmodel 中 livedata 的监听也是返回一个 state.

但这个 state 是不能像 compose 内的 state 直接修改的。要修改,需要调用 viewmodel 中的函数来间接修改。

尝试过的方案

示例代码

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

如果数据源来自网络呢

上面是使用本地 Room 的存储方案,如果使用网络数据,可以参考

https://github.com/ellisonchan/ComposeMovie

参考

https://stackoverflow.com/questions/61619408/livedata-in-combination-with-jetpack-compose

我是一名山东烟台的开发者,联系作者