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

文章目录

    思路

    对 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 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式