android - 如何在 Android ViewModel 中等待多个作业?
问题描述
给定以下组件
data class Account(val name: String)
data class GetAccountRequest(val name: String)
@Dao
interface AccountDao {
@Query("SELECT * FROM accounts ORDER BY name ASC")
fun all(): LiveData<List<Account>>
}
interface AccountOperations {
@GET("/foo/account")
suspend fun getAccount(@Body request: GetAccountRequest): Account
}
class AccountRepository(private val dao: AccountDao, private val api: AccountOperations) {
val accounts: LiveData<List<Account>> = dao.all()
suspend fun refresh(name: String) {
val account = api.getAccount(GetAccountRequest(name))
dao.insert(account)
}
}
我正在开发一个使用这些组件的 Android 应用程序(由 Room 支持数据库,Retrofit 支持 API 访问)。
在我的 ViewModel 中,我维护一个列出所有帐户的 RecyclerView。我允许用户手动刷新该列表。相应的(部分)ViewModel 如下所示:
fun refresh() {
viewModelScope.launch {
repository.accounts.value?.forEach {
launch { repository.refresh(it.name) }
}
}
Timber.i("Done refreshing!")
}
我确实希望刷新以并行更新所有帐户,这就是我使用launch
. 我还决定在 ViewModel 中而不是在存储库中执行此操作,因为这需要在存储库中启动一个新的协程。由于存储库没有自然的生命周期,因此不鼓励使用这篇文章。
上面的函数 ,refresh
是从 UI 调用的,并在 RecyclerView 更新时显示刷新指示符。所以我想在所有帐户都更新后停止这个指标。
我上面显示的代码没有这样做,因为它将启动所有更新,然后在所有更新完成之前打印日志语句。结果,尽管仍有更新,但刷新指示器消失了。
所以我的问题(最后)是:我如何重构代码以使其并行运行所有更新,但确保在所有更新refresh
完成之前不会返回?
编辑#1
回到我想要实现的目标:在视图更新时显示刷新指示器,我想出了以下内容(更改refresh
了 ViewModel 中的函数):
fun refresh() {
viewModelScope.launch {
try {
coroutineScope {
_refreshing.value = true
repository.accounts.value?.map { account ->
async {
repository.refresh(account.name)
}
}
}
} catch (cause: CancellationException) {
throw cause
} catch (cause: Exception) {
Timber.e(cause)
} finally {
_refreshing.value = false
}
}
}
ViewModel 在刷新时会公开一个 LiveData,片段可以观察它以显示或隐藏微调器。这似乎可以解决问题。但是,它仍然感觉不对,我很欣赏任何改进的解决方案。
解决方案
为了await
您的所有并行refresh()
操作,只需使用awaitAll()
:
coroutineScope.launch {
_refreshing.value = true
repository.accounts.value?.map { account ->
async {
repository.refresh(account.name)
}
}.awaitAll()
_refreshing.value = false
}
此外,不建议使用try/catch
. 您可以在此处阅读更多信息。
推荐阅读
- python - 根据条件修改 numpy 数组的值
- pine-script - 如何在 alertcondition() 中检查真/假结果
- json - 如何在android的sqlite中快速批量插入json数据
- javascript - 使用 onChange 更新父组件的状态
- javascript - 如何使本地网络上的 WebRTC 视频流正常工作?
- vim - Vim foldexpr匹配pattern1 OR pattern2?
- graphics - 如何在世界空间中进行遮挡剔除
- r - 在 r (frm) 中使用分数响应模型中的因子
- rust - 我可以在 Rust 中将不可变借用标记为独占吗?
- javascript - 如何使用javascript获取两个输入(类型时间)值(上午/下午)