我的架构如下:
Dao方法返回Flow<T>
:
@Query("SELECT * FROM table WHERE id = :id")
fun itemById(id: Int): Flow<Item>
存储层从数据库返回项目,但也从网络回填:
(**这里需要帮助-这无法正常工作**)
fun items(): Flow<Item> = flow {
// Immediately emit values from DB
emitAll(itemDao.itemById(1))
// Backfill DB via network request without blocking coroutine
itemApi.makeRequest()
.also { insert(it) }
}
ViewModel层接收流,应用所有转换,然后使用.asLiveData()将其转换为LiveData:
fun observeItem(): LiveData<Item> = itemRepository.getItemFlow()
.map { // apply transformation to view model }
.asLiveData()
观察LiveData发射并更新UI的片段:
viewModel.item().observeNotNull(viewLifecycleOwner) {
renderUI(it)
}
我遇到的问题是在步骤2上。我似乎无法找到一种构造逻辑的方法,这样我就可以立即从Flow中发射项目,而且无需等待即可执行网络提取。
由于从网络逻辑中获取数据是在同一个暂停函数中,因此它将等待网络请求完成,然后再向下游发出结果。但是我只想独立发出该请求,因为我对等待结果不感兴趣(当返回结果时,它将更新Room并自然获得结果)。
有什么想法吗?
编辑
Marko的解决方案对我来说效果很好,但是我确实尝试过类似的方法:
suspend fun items(): Flow<List<Cryptocurrency>> = coroutineScope {
launch {
itemApi.makeRequest().also { insert(it) }
}
itemDao.itemById(1)
}
答案 0 :(得分:1)
听起来您正在描述要启动的后台任务。为此,您需要访问协程范围,因此items()
应该是CoroutineScope
的扩展功能:
fun CoroutineScope.items(): Flow<Item> {
launch {
itemApi.makeRequest().also { insert(it) }
}
return flow {
emitAll(itemDao.itemById(1))
}
}
另一方面,如果您要启动远程提取,其结果也将成为响应的一部分,则可以按以下步骤进行操作:
fun items(): Flow<Item> = flow {
coroutineScope {
val lateItem = async { itemApi.makeRequest().also { insert(it) } }
emitAll(itemDao.itemById(1))
emit(lateItem.await())
}
}