← Назад к вопросам

В чем разница между LaunchedEffect и DisposableEffect?

1.8 Middle🔥 131 комментариев
#UI и вёрстка#Жизненный цикл и навигация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между LaunchedEffect и DisposableEffect

Оба эффекта являются частью Compose Side-Effect системы и предназначены для выполнения операций вне потока композиции UI, но решают разные задачи и имеют различные жизненные циклы.

Ключевое концептуальное различие

LaunchedEffect предназначен для запуска корутин (приостанавливающих операций), которые должны выполняться в рамках жизненного цикла composable-функции. Он автоматически отменяет корутину при выходе из композиции.

DisposableEffect предназначен для подписки на внешние ресурсы или наблюдаемые объекты, требующие явного освобождения (dispose). Он выполняет cleanup-логику при уничтожении или рекомпозиции с измененными ключами.

LaunchedEffect: для асинхронных операций

@Composable
fun TimerExample() {
    var seconds by remember { mutableStateOf(0) }
    
    // Запускаем корутину при входе в композицию
    LaunchedEffect(Unit) {
        while (true) {
            delay(1000)
            seconds++
        }
    }
    
    Text(text = "Прошло секунд: $seconds")
}

Характеристики LaunchedEffect:

  • Автоматический запуск корутины при входе в композицию
  • Автоматическая отмена при выходе из композиции
  • Принимает ключи (keys) - при их изменении предыдущая корутина отменяется и запускается новая
  • Не имеет блока cleanup - отмена корутины происходит автоматически
  • Идеален для: анимаций, загрузки данных, таймеров, обработки событий жизненного цикла

DisposableEffect: для ресурсов с cleanup

@Composable
fun SensorExample() {
    val context = LocalContext.current
    var sensorValue by remember { mutableStateOf(0f) }
    
    DisposableEffect(Unit) {
        // Инициализация ресурса
        val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
        val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        
        val listener = object : SensorEventListener {
            override fun onSensorChanged(event: SensorEvent) {
                sensorValue = event.values[0]
            }
            override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
        }
        
        sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
        
        // Блок cleanup - выполнится при уничтожении
        onDispose {
            sensorManager.unregisterListener(listener)
        }
    }
    
    Text(text = "Значение сенсора: $sensorValue")
}

Характеристики DisposableEffect:

  • Требует блока onDispose для очистки ресурсов
  • Выполняется синхронно (не запускает корутины автоматически)
  • Ключи определяют переинициализацию - при изменении ключей выполняется cleanup и эффект запускается заново
  • Идеален для: подписок на BroadcastReceiver, слушателей событий, регистрации в системных сервисах, кастомных очисток

Сравнительная таблица

АспектLaunchedEffectDisposableEffect
Основное назначениеЗапуск корутинУправление ресурсами с cleanup
Автоматическая отменаДа (для корутин)Нет (требует явного onDispose)
Возвращаемое значениеНетDisposableEffectResult
КорутиныЗапускает автоматическиНе запускает автоматически
Cleanup логикаНетОбязательный блок onDispose
Использование с ключамиПерезапуск при измененииПереинициализация при изменении

Практические сценарии использования

Когда использовать LaunchedEffect:

  • Загрузка данных из сети/БД при монтировании компонента
  • Запуск анимаций или таймеров
  • Реакция на изменения состояния с асинхронными операциями
  • Навигация после завершения асинхронной операции

Когда использовать DisposableEffect:

  • Регистрация BroadcastReceiver
  • Подписка на Flow/LiveData из ViewModel
  • Работа с системными сервисами Android (сенсоры, локация)
  • Кастомные подписки на события, требующие отписки
  • Управление жизненным циклом сторонних библиотек

Важные нюансы

  1. Ключи (keys) у обоих эффектов работают одинаково - эффект перезапускается при изменении любого ключа
  2. Не использовать для UI-логики - оба эффекта выполняются вне потока композиции
  3. DisposableEffect может содержать корутины, но их нужно отменять в onDispose:
DisposableEffect(key1) {
    val job = CoroutineScope(Dispatchers.IO).launch {
        // асинхронная работа
    }
    
    onDispose {
        job.cancel() // Явная отмена корутины
        // Другая очистка
    }
}

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

В чем разница между LaunchedEffect и DisposableEffect? | PrepBro