从房间发出协程流,同时通过网络请求回填



我的架构是这样的:

  1. 道方法返回Flow<T>

    @Query("SELECT * FROM table WHERE id = :id")
    fun itemById(id: Int): Flow<Item>
    
  2. 存储库层从数据库返回项目,但也从网络回填:

    (*在这里需要帮助 - 这没有按预期工作**(

    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) }
    }
    
  3. ViewModel 层获取流程,应用任何转换,并使用 .asLiveData(( 将其转换为 LiveData:

    fun observeItem(): LiveData<Item> = itemRepository.getItemFlow()
    .map { // apply transformation to view model }
    .asLiveData()
    
  4. 观察实时数据排放和更新 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)
}

听起来您正在描述要启动的后台任务。为此,您需要访问协程作用域,因此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())
}
}

最新更新