Какие знаешь виды скоупов в корутинах?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие знаешь виды скоупов в корутинах
Коротутины в Kotlin используют coroutine scopes для управления жизненным циклом асинхронных операций. Это критически важно для правильного управления памятью и отмены операций.
1. GlobalScope (Глобальный скоп)
Коротутина живет столько же, сколько приложение. Это отличный пример антипаттерна.
GlobalScope.launch {
val data = apiService.fetchData()
}
Почему это плохо:
- Невозможно отменить операцию
- Memory leak при закрытии Activity
- Могут возникнуть UnhandledJobException
- Сложно тестировать
2. ViewModelScope (для MVVM)
Привязан к жизненному циклу ViewModel. Это рекомендуемый подход для Android.
class UserViewModel : ViewModel() {
fun refreshUser() {
viewModelScope.launch {
try {
val user = userRepository.getUser(1)
} catch (e: Exception) {
handleError(e)
}
}
}
}
Преимущества:
- Автоматическая отмена при destroy ViewModel
- Привязан к жизненному циклу
- Встроена обработка ошибок
3. LifecycleScope (для Activity/Fragment)
Привязан к жизненному циклу Activity или Fragment.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
val data = fetchData()
updateUI(data)
}
}
}
Состояния Lifecycle:
- CREATED
- STARTED
- RESUMED
4. Custom Scope (Пользовательский скоп)
Для полного контроля жизненного цикла корутин.
class CustomRepository {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
fun loadData(onResult: (String) -> Unit) {
scope.launch {
val data = fetchDataFromApi()
onResult(data)
}
}
fun cancel() {
scope.cancel()
}
}
5. Dispatchers (Выполнение контекст)
Диспетчеры определяют на каком потоке выполняется корутина.
withContext(Dispatchers.Main) {
updateUI()
}
val data = withContext(Dispatchers.IO) {
database.getUser(1)
}
val result = withContext(Dispatchers.Default) {
expensiveCalculation(data)
}
Рекомендуемые диспетчеры:
- Dispatchers.Main — UI операции
- Dispatchers.IO — сеть, БД, файлы
- Dispatchers.Default — CPU-bound операции
6. SupervisorJob (для иерархии)
Для обработки ошибок без отмены других корутин.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
scope.launch {
throw Exception()
}
scope.launch {
println("This WILL print")
}
Это важно когда ошибка в одной корутине не должна отменить другие.
7. Scope с обработкой ошибок
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
handleError(exception)
}
val scope = CoroutineScope(
Job() + Dispatchers.Main + exceptionHandler
)
Экспешны автоматически обрабатываются для всех корутин.
Сравнение скопов
| Скоп | Жизненный цикл | Когда использовать | Отмена |
|---|---|---|---|
| GlobalScope | приложение | Только тесты | Никогда |
| ViewModelScope | ViewModel | MVVM | Автоматична |
| LifecycleScope | Activity/Fragment | UI операции | Автоматична |
| Custom | Ручная | Полный контроль | Ручная |
| SupervisorJob | Иерархия | Независимые задачи | Независимая |
Лучшие практики
Запрещено:
- Никогда не используй GlobalScope в production коде
Рекомендуется:
- ViewModelScope для UI-related операций
- LifecycleScope для Fragment/Activity
- SupervisorJob для независимых задач
- Всегда обрабатывай исключения
- Правильно выбирай Dispatcher
- Отменяй корутины в onDestroy()
Выбор правильного скопа критичен для избежания memory leaks и правильного управления асинхронными операциями в Android.