繁体   English   中英

如何观察在初始化/构造函数期间未初始化的 ViewModel 的 LiveData(房间挂起功能)

[英]How to observe LiveData of a ViewModel that is not initialized during init / constructor (Room suspend function)

我的ViewModel在协程中通过Room加载数据:

// ViewModel:
lateinit var items : LiveData<List<Item>>
    private set

init {
    viewModelScope.launch(IO) {
        items = MyDatabase.getInstance(MyApplication.getContext()).itemsDao.getAllItems()
    }
}

// Fragment:
viewModel.items.observe(viewLifecycleOwner, Observer {
    it?.let {
        adapter.submitList(it)
    }
})

这将导致

kotlin.UninitializedPropertyAccessException: lateinit property items has not been initialized

我理解这个错误 - Fragment尝试在协程完成之前访问items属性,很好。

但是我该如何解决呢? 如何观察协程在稍后时间点实际提供的ViewModel的数据? 请注意,我希望我的查询itemsDao.getAllItems()保持暂停 function (没有 UI 冻结)。

使用返回LiveData的 Dao 方法时,您根本不需要使用viewModelScope.launch(IO) - 返回LiveData根本不会真正查询数据库,直到您开始observe() LiveData (此时它使用内部唯一的ArchTaskExecutor从主线程运行查询)。

因此,这里根本没有理由使用lateinit var 您可以直接设置LiveData

val items = MyDatabase.getInstance(MyApplication.getContext()).itemsDao.getAllItems()

您还应该强烈考虑扩展AndroidViewModel ,它会在构造函数中为您提供Application上下文,而不是依赖MyApplication.getContext()

添加在视图模型初始化时创建的MediatorLiveData 然后将您的主要LiveData作为源添加到它。

val items = MediatorLiveData<List<Item>>()

init {
    viewModelScope.launch(IO) {
        val dbItems = MyDatabase.getInstance(MyApplication.getContext()).itemsDao.getAllItems()
        items.addSource(dbItems) { items.postValue(it) }
    }
}

官方文档中的更多解释:

LiveData 子类,它可以观察其他 LiveData 对象并对来自它们的 OnChanged 事件作出反应。 此 class 正确地将其活动/非活动状态向下传播到源 LiveData 对象。

如果您需要获取大量物品。 我认为您可以尝试像此文档一样emit实时数据。

视图模型:

fun items(): LiveData<List<Item>> = liveData(Dispatchers.IO) {
    emit(MyDatabase.getInstance(MyApplication.getContext()).itemsDao.getAllItems())
}

分段:

viewModel.items.observe(viewLifecycleOwner, Observer {
    it?.let {
        adapter.submitList(it)
    }
})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM