Не стоит использовать CoroutineScope, отвязанный от приложенияПорой в коде встречается ситуация, когда для запуска корутины в репозитории или каком-либо менеджере разработчики создают CoroutineScope:
class MyRepository(...) {
private val scope = CoroutineScope()
fun doWork(...) {
scope.launch { /* длительная работа */ }
}
}
Но есть вариант хуже:
class MyRepository(...) {
fun doWork(...) {
CoroutineScope(...).launch { /* длительная работа */ }
}
}
0️⃣ CoroutineScope не должен создаваться для запуска только одной корутины.
‼️1️⃣ При создании
CoroutineScope
следует добавить Job (или SupervisorJob), а также
CoroutineDispatcher
, который будет использоваться по умолчанию.
2️⃣ CoroutineScope должен быть связан с каким-либо жизненным циклом объекта. Вся суть scope заключается в том, чтобы отменять операции, когда они больше не нужны. Например, viewModelScope привязан к жизни ViewModel. В Android приложениях я всегда создаю Scope, связанный с Android Application классом, - AppScope. Либо использовать AppScope в классах, где нужен scope, либо сделать scope, который будет связан с другим CoroutineScope приложения.
Создать дочерний Scope можно следующим образом:
fun CoroutineScope.childScope(
context: CoroutineContext = EmptyCoroutineContext
): CoroutineScope {
return CoroutineScope(
coroutineContext
+ SupervisorJob(parent = coroutineContext[Job])
+ context
)
}
3️⃣ Вам точно нужен запуск корутины? Или подойдет suspend функция? Определитесь, почему асинхронный код должен работать независимо от вызывающего его кода и не иметь возможности получения информации об окончании работы через suspend. Также можно возвращать объект Job (хотя это спорная практика, на мой взгляд).
4️⃣ Не используйте
GlobalScope
.
‼️ Это наследие старых корутин, когда ещё не было structured concurrency.
Что можете посоветовать вы авторам подобного кода, помимо почитать документацию и курсы? Пишите в комментариях.
#kotlin #coroutines