如何在Android ViewModel中等待多个作业?

问题描述 投票:0回答:1

给出以下组件

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中而不是在存储库中执行此操作,因为这将需要在存储库中启动新的协程。不建议使用每个this post,因为存储库没有自然的生命周期。

上述函数refresh从UI调用,并在更新RecyclerView时显示刷新指示器。因此,一旦所有帐户均已更新,我想停止此指示器。

我上面的代码没有执行此操作,因为它会启动所有更新,然后在所有更新完成之前打印日志语句。结果,尽管仍有更新,刷新指示消失了。

所以,我的问题(最终)是:我该如何重构代码,以使其并行运行所有更新,但确保refresh在所有更新完成之前不返回?

编辑#1

回到我要实现的目标:在视图更新时显示刷新指示器,我提出了以下内容(在ViewModel中更改了refresh函数:]

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,并且片段可以观察它以显示或隐藏微调器。这似乎可以解决问题。但是,它仍然感觉不对,我感谢任何改进的解决方案。

鉴于以下组件,数据类Account(val名称:String)数据类GetAccountRequest(val name:String)@Dao接口AccountDao {@Query(“ SELECT * FROM accounts ORDER BY name ASC”)...

android kotlin android-architecture-components coroutine kotlin-coroutines
1个回答
0
投票

为了对所有并行await操作进行refresh(),只需使用awaitAll()

© www.soinside.com 2019 - 2024. All rights reserved.