У меня есть следующий метод в моей модели представления, который вызывает вариант использования приостановки.
fun clearFirebaseCache() {
viewModelScope.launch {
clearFirebaseCacheUseCase.execute()
}
}
И в моей MainActivity это называется так:
mMainViewModel.changeLanguageConsumableLiveData
.observeAndConsume(this) {
lifecycleScope.launch {
mMainViewModel.clearFirebaseCache()
ProcessPhoenix.triggerRebirth(this@MainActivity)
}
}
Поскольку функцияclearFirebaseCache() должна сначала завершиться перед вызовом ProcessPhoenix.triggerRebirth, я добавил Deferred, чтобы дождаться его завершения первым.
Однако мне это не нравится Deferred<Unit>, и я бы предпочел запуск, поскольку он просто очищает кеш и ничего не возвращает.
Я думаю, что это должно быть в launch, поскольку он ничего не возвращает, это всего лишь один раз. Но поскольку мне приходится запускать их последовательно, я не знаю другого способа.
Еще одна вещь: наличие этого Deferred делает его более запутанным, поскольку, если я хочу использовать его где-нибудь еще, мне всегда придется вызывать await, даже если у меня нет никаких последовательных вызовов.
Это окончательное решение
Take in a lamba that will be called after cleared cache
fun clearFirebaseCache() {
viewModelScope.launch {
clearFirebaseCacheUseCase.execute()
}
}
И используя его вот так, не уверен, хороший это шаблон или нет.
mMainViewModel.changeLanguageConsumableLiveData
.observeAndConsume(this) {
lifecycleScope.launch {
mMainViewModel.clearFirebaseCache(waitUntilComplete = {
ProcessPhoenix.triggerRebirth(this@MainActivity)
})
}
}
Ожидание завершения функции приостановки — это поведение по умолчанию при ее вызове, нам не нужны никакие отсрочки, launch() и т. д.:
suspend fun clearFirebaseCache(): Unit {
clearFirebaseCacheUseCase.execute()
}
Затем:
mMainViewModel.clearFirebaseCache()
ProcessPhoenix.triggerRebirth(this@MainActivity)
Так просто, как, что.
Ваш подход с Deferred или обратным вызовом тоже должен работать, но это традиционное решение, и сопрограммы были изобретены специально для замены таких шаблонов лучшей альтернативой. Как мы видим в приведенном выше примере, код значительно упрощается за счет использования функции приостановки и ее прямого вызова.
Имейте в виду, что clearFirebaseCacheUseCase теперь будет выполняться в lifecycleScope вместо viewModelScope. Поэтому убедитесь, что clearFirebaseCacheUseCase также работает должным образом при отмене этой области, что может произойти в любой момент (при изменении конфигурации, например). Также стоит посмотреть: developer.android.com/kotlin/coroutines/…
@ ant2009 ant2009 Да, я это имел в виду. Нам все равно нужно запустить его, используя некоторую область видимости, например. нам нужно выполнить его из обработчика событий. Но после того, как мы попадем в мир сопрограмм, мы можем напрямую вызывать функции приостановки, а это означает, что мы ждем их.
@Leviathan Да, я не был уверен, стоит ли мне вдаваться в такие подробности, потому что главный вопрос здесь заключался в том, как дождаться функции приостановки. В данном конкретном случае важно учитывать, кто является «владельцем» фонового процесса и если его больше никто не ждет, то следует ли его продолжать или отменить.
@Левиафан и Брут, мне просто интересно, у меня здесь 2 прицела. lifecycleScope и viewModelScope. Причина, по которой я использую lifecycleScope, заключается в том, что я могу вызвать функцию приостановки в viewModel, которая использует viewModelScope. Таким образом, по умолчанию для запуска сопрограммы будет использоваться lifecycleScope или это будет viewModelScope. Могу ли я узнать, какая область будет использоваться. Я думаю, что это будет viewModelScope, поскольку он последний, который запускает вариант использования.
В исходной версии для выполнения варианта использования использовался viewModelScope. Пока вы не отредактировали свой вопрос, чтобы удалить Deferred, жизненный цикл был необходим для развертывания этого Deferred. После вашего редактирования он просто запускает ClearFirebaseCache и триггерRebirth асинхронно в фоновом режиме, чтобы не блокировать основной поток. В решении @broot viewModelScope вообще не задействован, все выполняется в жизненном цикле. Это довольно просто: всегда используется используемая область видимости, которая фактически запускает сопрограмму с помощью launch (или async).
Я использовал ваше решение вот так
lifecycleScope.launch { mMainViewModel.clearFirebaseCache() ProcessPhoenix.triggerRebirth(this@MainActivity) }