> Какие методы жизненного цикла приложения во Flutter используются для отслеживания сворачивания и разворачивания (Flutter, Android)
Уровень: senior · Роль: mobile · Категория: Технические вопросы
Компании: PashaPay
Стек: Flutter, Android
> Пример ответа
Короткий ответ
Во Flutter отслеживание сворачивания и разворачивания приложения выполняется через WidgetsBindingObserver и метод didChangeAppLifecycleState(). Он возвращает значения AppLifecycleState.inactive, paused, resumed, detached и hidden. Для Android-специфичных сценариев также можно использовать AppLifecycleListener (новый API) или нативные колбэки через MethodChannel.
Подробное объяснение
Основной механизм - подписка на изменения жизненного цикла через WidgetsBinding.instance.addObserver(this) в State-классе. Метод didChangeAppLifecycleState вызывается при каждом переходе состояния.
Состояния AppLifecycleState:
resumed- приложение активно и видимо, пользователь взаимодействуетinactive- приложение видимо, но не получает события (например, при звонке, свайпе шторки)paused- приложение свернуто, не видимо (AndroidonPause/onStop)detached- приложение ещё прикреплено к движку, но будет уничтожено (AndroidonDetachedFromWindow)hidden- появилось в Flutter 3.13, означает что приложение скрыто, но может быть в состоянииinactiveилиpaused
Важно: на Android переход в фоновый режим обычно даёт последовательность inactive → hidden → paused. При возврате - resumed.
Также существует AppLifecycleListener (Flutter 3.13+), который предоставляет более удобный API с отдельными колбэками: onResume, onPause, onInactive, onHide, onShow, onDetach, onRestart (для Android).
На практике
Типичный сценарий - сохранение состояния, остановка анимаций, закрытие WebSocket-соединений при сворачивании, и восстановление при разворачивании.
Для Android-специфичных кейсов (например, отслеживание onUserLeaveHint или onTrimMemory) потребуется MethodChannel или использование ActivityAware из плагинов.
Важно помнить: didChangeAppLifecycleState не гарантирует вызов при каждом переходе на Android - например, при повороте экрана может быть только inactive без paused.
Пример кода
class AppLifecycleObserver extends StatefulWidget { const AppLifecycleObserver({super.key, required this.child}); final Widget child; @override State<AppLifecycleObserver> createState() => _AppLifecycleObserverState(); } class _AppLifecycleObserverState extends State<AppLifecycleObserver> with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { case AppLifecycleState.resumed: // восстановить соединения, перезапустить анимации break; case AppLifecycleState.inactive: // приостановить тяжёлые операции break; case AppLifecycleState.paused: // сохранить состояние, закрыть WebSocket break; case AppLifecycleState.hidden: // скрыть чувствительные данные break; case AppLifecycleState.detached: // финальная очистка break; } } @override Widget build(BuildContext context) => widget.child; }
Альтернатива через AppLifecycleListener:
late final AppLifecycleListener _listener; @override void initState() { super.initState(); _listener = AppLifecycleListener( onResume: () => _handleResume(), onPause: () => _handlePause(), onHide: () => _handleHide(), onShow: () => _handleShow(), onInactive: () => _handleInactive(), onDetach: () => _handleDetach(), onRestart: () => _handleRestart(), // Android only ); } @override void dispose() { _listener.dispose(); super.dispose(); }
Как отвечать на собеседовании
Начните с WidgetsBindingObserver и didChangeAppLifecycleState. Перечислите все состояния и их значение на Android. Упомяните, что на Android порядок состояний может отличаться от iOS. Добавьте про AppLifecycleListener как более современный API. Приведите пример практического использования - сохранение черновика или остановка стриминга. Если спросят про глубину - упомяните MethodChannel для нативных колбэков.
Что проверяет интервьюер
- Понимание разницы между
inactive,pausedиhidden - Знание порядка вызовов на Android и iOS
- Умение корректно подписываться и отписываться от observer
- Понимание, что
didChangeAppLifecycleStateне покрывает все Android-сценарии (например,onTrimMemory) - Знание современного API
AppLifecycleListener
Типичные ошибки
- Забывают удалить observer в
dispose- утечка памяти - Путают
inactiveиpaused, считая их эквивалентами - Полагают, что
pausedвсегда вызывается при сворачивании - на Android бывает толькоinactive+hidden - Пытаются выполнять тяжёлые операции в
didChangeAppLifecycleState- это блокирует UI - Не учитывают, что при повороте экрана на Android вызывается
inactive, но неpaused - Используют
WidgetsBindingObserverвStatelessWidgetбезState- observer требует жизненный циклState
> Похожие задачи по mobile
Как во Flutter взаимодействовать с нативным кодом платформы для обмена данными
Как реализовать работу в фоне во Flutter для отправки данных при возобновлении связи
Какие пакеты для локального хранения данных во Flutter использовать
Какие возможности есть у bloc из коробки во Flutter
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью