[英]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.