我正在尝试使用房间的新流支持和改造的协程支持来实现一个完整的存储库。我正在处理一些我似乎找不到解决方案的问题。
所以首先,让我们说明我到目前为止的位置。这是我的 ViewModel 类:
class InvViewModel : ViewModel() {
val repo = Repository()
val flow = flow {
emit(Lce.Loading())
val result = repo.updateInv()
repo.getInv().collect { inv ->
result?.let { exception ->
emit(Lce.Error<List<Inv>>(inv, exception))
} ?: emit(Lce.Content(inv))
}
}
fun getLocalInv() = flow.asLiveData()
fun updateInv() =
viewModelScope.launch {
repo.updateInv()
}
}
在这个类中,我创建了一个设置加载状态的流,从网络请求远程数据,当它获得结果时它订阅房间数据库并将自动从数据库返回的流转换为知道状态的流网络调用以及来自数据库的数据。
这有什么问题以及我似乎无法解决的问题是以下两个问题:
1)通过像这样构造我的代码,我必须等待网络响应才能发出任何数据。我想要实现的是从房间数据库返回流并显示旧数据,触发网络更新并用新数据更新 ui。但是我需要以这种方式构造我的代码,因为这是我能想到的唯一方法,它可以告诉 UI 网络调用是否失败。
2)此代码在技术上只能在第一次执行并且网络调用没有失败的情况下工作。如果我想手动触发更新,我不能,因为流仅在第一次收集(所以第一次执行)或房间数据库发出更改时运行(所以如果网络没有失败并且我将结果保存到D b)。
如果你需要它,repo 代码是这样的:
val database = Database.getDb()
val remote = RemoteDataSource()
fun getInv(): Flow<List<Inv>> = database.invDao().getInv()
suspend fun updateInv(): Exception? {
return try {
val inv = remote.getInv()
database.invDao().saveInvs(inv)
null
} catch (e: Exception) {
e.printStackTrace()
e
}
}
哪里remote.getInv()
只是一个改造挂起协程和 database.invDao() 是:
@Dao
interface InvDao {
@Query("SELECT * FROM Inv")
fun getInv(): Flow<List<Inv>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveInv(inv: Inv)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveInvs(invs: List<Inv>)
}
如果不是推荐的方法,我不需要将所有数据放在一个流中,我只需要知道使用带有流和改造协程的空间来实现一个好的存储库的正确方法是什么,并且拥有db 作为唯一的事实来源。