Можно ли в определенных ситуациях запускать сопрограммы из Globalscope на Android (синглтоны)? - PullRequest
0 голосов
/ 17 июня 2019

При запуске сопрограмм из ViewModels «Компоненты действий», «Фрагменты» или «Архитектура Android» имеет смысл использовать область сопрограмм, связанную с жизненным циклом этого компонента представления, чтобы избежать утечек и свободных ресурсов, например отмена сетевого запроса, когда пользователь покидает экран.

Но есть и другие ситуации, когда вы не хотите отменять сопрограмму, даже когда пользователь покидает экран, например, когда вы выполняете сетевой запрос на аналитику или записываете в базу данных. Можно ли запускать сопрограммы с GlobalScope в таких ситуациях? Объекты, в которых запускаются эти сопрограммы, в основном Singletons, поэтому они все равно живут в течение всего срока службы приложения, так что опасности утечки нет, верно?

Документы Kotlin в GlobalScope достаточно ясны:

Код приложения обычно должен использовать определенный приложением CoroutineScope. Использование асинхронного или запуска на экземпляре GlobalScope крайне не рекомендуется.

Можно ли использовать GlobalScope в этих ситуациях? Если нет, то как должен выглядеть мой определяемый приложением CoroutineScope?

Ответы [ 2 ]

1 голос
/ 18 июня 2019

Если у вас есть асинхронный работник, жизненный цикл которого действительно глобален (они умирают / заканчиваются, когда ваш процесс умирает), то можно использовать GlobalScope или аналогичную область действия на всю жизнь, это нормально.

Скажем, у вас есть активность, которая делает запрос, но фактический сетевой запрос должен продолжаться, даже если активность уходит, потому что вы хотели бы кэшировать его, когда сеть, наконец, вернет ответ.

Вы добавите CoroutineScope к вашей Деятельности / Фрагменту или лучше к вашей ViewModel и получите свой код, который, наконец, помещает материал на экран в этой области.Когда Activity / Fragment / ViewModel умирает, область действия отменяется, и на экране больше не будет попытки показать что-то, что больше не существует.

Однако ваша Fragment / Activity / ViewModel может общаться с источником данных./ репозиторий, жизненный цикл которого заканчивается только после завершения процесса.Вы можете переключиться на GlobalScope там , чтобы ваши сетевые ответы кэшировались, даже когда ни одна Activity / Fragment / ViewModel не активна, чтобы показать результат на экране.

class MyViewModel(context: CoroutineContext, repo: MyRepository) : ViewModel() {
    private val scope: CoroutineScope(context + SuperviserJob())

    override fun onCleared() { scope.cancel() }

    fun getDataFromNetwork() {
        scope.launch {
            myLiveData.value = repo.getDataFromNetwork()
        }
    }

}

// Singleton class
class MyRepositoryImpl(context: CoroutineContext) : MyRepository {
    private val scope: CoroutineScope(context + SupervisorJob())

    override suspend fun getDataFromNetwork() : String {
        return scope.async { // switch scopes
            val data = ... fetch data ...
            saveInCache(data)
        }.await()
    }
}

Когда ваша ViewModel заканчивается (вызывается onCleared), MyRepositoryImpl getDataFromNetwork продолжает работать и будет вызывать saveInCache, если все пойдет правильно.Однако возвращенное значение не будет присвоено myLiveData.value, поскольку сопрограмма области видимости вашей модели ViewModel была отменена.

0 голосов
/ 17 июня 2019

Учитывая, что вы уже пытаетесь подключить его к жизненному циклу приложения, я бы предложил либо передать область действия вашему синглтону, либо внедрить им сопрограмму.К сожалению, запуск сопрограмм в GlobalScope по-прежнему может привести к утечкам.Смотрите эту замечательную статью Романа Елизарова для дополнительной информации: https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc

...