Каждое мобильное приложение живет своей собственной жизнью: его могут открыть, свернуть, перейти в другое приложение, вернуться через минуту или через час. Чтобы корректно реагировать на эти события, Flutter-приложение условно проходит через ряд состояний, которые определяются перечислением
AppLifecycleState:✔️
resumed — приложение находится на переднем плане, видно на экране и готово к взаимодействию с пользователем✔️
inactive — приложение временно неактивно, например, при поступлении звонка. Оно не получает событий от пользователя✔️
paused — приложение уходит в фон, становится невидимым и не реагирует на действия пользователя. В это время стоит приостанавливать ресурсоемкие процессы✔️
hidden — приложение скрыто от пользователя. Процесс остается в памяти и готов к быстрому возобновлению. На некоторых платформах это состояние заменяет paused✔️
detached — приложение больше не активно и готовится к завершениюЧтобы отслеживать изменения этих состояний, используется
WidgetsBindingObserver. Его метод didChangeAppLifecycleState вызывается каждый раз, когда система переводит приложение между состояниями. Соответственно, мы можем реагировать на его изменения: обновлять данные, останавливать процессы, освобождать ресурсы или, наоборот, перезапускать необходимые операции.Для регистрации наблюдателя нужно добавить миксин
WidgetsBindingObserver к классу, далее вызвать WidgetsBinding.instance.addObserver(this); в методе initState.Работа с самим didChangeAppLifecycleState выглядит так:
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
setState(() {
if (state == AppLifecycleState.resumed) {
appState = 'Возобновлено';
} else if (state == AppLifecycleState.inactive) {
appState = 'Неактивно';
} else if (state == AppLifecycleState.paused) {
appState = 'Приостановлено';
} else if (state == AppLifecycleState.detached) {
appState = 'Отключено';
} else if (state == AppLifecycleState.hidden) {
appState = 'Скрыто';
}
});
}
Представим ситуацию: у нас подключены OTA-переводы, и требуется обновлять их как при запуске приложения, так и каждый раз, когда пользователь возвращается на экран из состояния
hidden. Для этого в состоянии resumed мы повторно вызываем метод для их обновления:class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_updateTranslations();
}
void _updateTranslations() {
...
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.resumed) {
_updateTranslations();
}
}
}
При работе с жизненным циклом приложения стоит учитывать несколько моментов:
▪️ состояния
paused и inactive могут вести себя по-разному на разных платформах, поэтому не всегда стоит запускать в них ресурсоемкие операции▪️ в состоянии
hidden приложение остается в памяти, но интерфейс еще может быть не готов, поэтому лучше не обращаться к виджетам до полной инициализации▪️ метод
didChangeAppLifecycleState вызывается в главном потоке UI, поэтому любые тяжелые операции стоит выполнять асинхронно или через отдельные сервисы, чтобы не блокировать интерфейс❤️ — если было полезно
