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

更新日期: 2021-09-18 阅读次数: 197 字数: 563 分类: Android

思路

对 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

tags: Jetpack Compose

爱评论不评论