Новый способ прослушивания событий жизненного цикла приложения во Flutter

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

"Старый" способ

До Flutter 3.13 прослушивать события жизненного цикла можно с помощью миксина WidgetsBindingObserver. Для этого пришлось бы добавить WidgetsBindingObserver в класс State и переопределить didChangeAppLifecycleState метод. В idChangeAppLifecycleState можно прослушивать события жизненного цикла, используя предоставленное значение состояния (AppLifecycleState).

class AppLifecyclePageOld extends StatefulWidget {
  const AppLifecyclePageOld({super.key});

  @override
  State<AppLifecyclePageOld> createState() => _AppLifecyclePageOldState();
}

class _AppLifecyclePageOldState extends State<AppLifecyclePageOld>
    // Use the WidgetsBindingObserver mixin
    with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();

    // Register your State class as a binding observer
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    // Unregister your State class as a binding observer
    WidgetsBinding.instance.removeObserver(this);

    super.dispose();
  }

  // Override the didChangeAppLifecycleState method and
  // listen to the app lifecycle state changes
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);

    switch (state) {
      case AppLifecycleState.detached:
        _onDetached();
      case AppLifecycleState.resumed:
        _onResumed();
      case AppLifecycleState.inactive:
        _onInactive();
      case AppLifecycleState.hidden:
        _onHidden();
      case AppLifecycleState.paused:
        _onPaused();
    }
  }

  void _onDetached() => print('detached');

  void _onResumed() => print('resumed');

  void _onInactive() => print('inactive');

  void _onHidden() => print('hidden');

  void _onPaused() => print('paused');

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Placeholder(),
    );
  }
}

Давайте посмотрим, как мы можем прослушивать события жизненного цикла приложения, используя новый класс AppLifecycleListener.

Кстати, "старый" способ прослушивания событий жизненного цикла все еще доступен. Фактически, AppLifecycleListener под капотом использует миксин WidgetsBindingObserver.

"Новый" способ

AppLifecycleListener - это класс, который вы можете использовать для прослушивания событий жизненного цикла приложения без необходимости напрямую использовать миксин WidgetsBindingObserver . Для этого создайте экземпляр класса  AppLifecycleListener  и передайте все колбэки, которые вы хотите прослушать.

class AppLifecyclePage extends StatefulWidget {
  const AppLifecyclePage({super.key});

  @override
  State<AppLifecyclePage> createState() => _AppLifecyclePageState();
}

class _AppLifecyclePageState extends State<AppLifecyclePage> {
  late final AppLifecycleListener _listener;

  @override
  void initState() {
    super.initState();

    // Initialize the AppLifecycleListener class and pass callbacks
    _listener = AppLifecycleListener(
      onStateChange: _onStateChanged,
    );
  }

  @override
  void dispose() {
    // Do not forget to dispose the listener
    _listener.dispose();

    super.dispose();
  }

  // Listen to the app lifecycle state changes
  void _onStateChanged(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.detached:
        _onDetached();
      case AppLifecycleState.resumed:
        _onResumed();
      case AppLifecycleState.inactive:
        _onInactive();
      case AppLifecycleState.hidden:
        _onHidden();
      case AppLifecycleState.paused:
        _onPaused();
    }
  }

  void _onDetached() => print('detached');

  void _onResumed() => print('resumed');

  void _onInactive() => print('inactive');

  void _onHidden() => print('hidden');

  void _onPaused() => print('paused');

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Placeholder(),
    );
  }
}

Есть ли разница?

Как можете заметить, "старый" и "новый" способы прослушивания событий жизненного цикла приложения очень похожи. Однако, чтобы понять главное преимущество  класса AppLifecycleListener , давайте взглянем на диаграмму конечного автомата жизненного цикла приложения Flutter:

На этой диаграмме показаны все возможные состояния приложения Flutter. Стрелки показывают возможные переходы между состояниями. При переопределении метода didChangeAppLifecycleState ("старый" способ) вы могли прослушивать только фактическое изменение состояния, например, когда ваше приложение перешло в resumed состояние. Однако вы не смогли прослушать переходы между состояниями, например, переходило ли ваше приложение в resumed состояние из состояния inactive или detached. Теперь класс AppLifecycleListener  позволяет это сделать:

class AppLifecyclePage extends StatefulWidget {
  const AppLifecyclePage({super.key});

  @override
  State<AppLifecyclePage> createState() => _AppLifecyclePageState();
}

class _AppLifecyclePageState extends State<AppLifecyclePage> {
  late final AppLifecycleListener _listener;

  @override
  void initState() {
    super.initState();

    // Pass all the callbacks for the transitions you want to listen to
    _listener = AppLifecycleListener(
      onDetach: _onDetach,
      onHide: _onHide,
      onInactive: _onInactive,
      onPause: _onPause,
      onRestart: _onRestart,
      onResume: _onResume,
      onShow: _onShow,
      onStateChange: _onStateChanged,
    );
  }

  @override
  void dispose() {
    _listener.dispose();

    super.dispose();
  }

  void _onDetach() => print('onDetach');

  void _onHide() => print('onHide');

  void _onInactive() => print('onInactive');

  void _onPause() => print('onPause');

  void _onRestart() => print('onRestart');

  void _onResume() => print('onResume');

  void _onShow() => print('onShow');

  void _onStateChanged(AppLifecycleState state) {
    // Track state changes
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Placeholder(),
    );
  }
}

В этом главное преимущество класса AppLifecycleListener. Он позволяет прослушивать переходы между состояниями жизненного цикла и выполнять необходимый код только для интересующих вас переходов.

Но есть еще одна вещь...

Колбэк onExitRequested

У класса AppLifecycleListener есть еще один колбэк onExitRequested. Он используется для запроса у приложения, позволит ли оно выйти в случаях, когда выход можно отменить. Например, его можно использовать для приложений macOS, где пользователь пытается закрыть приложение, если есть несохраненные изменения:

Чтобы отменить запрос на выход, вам необходимо вернуть из колбэка  onExitRequested  параметр AppExitResponse.cancel. В противном случае верните AppExitResponse.exit, чтобы разрешить приложению завершить работу.

class AppLifecyclePage extends StatefulWidget {
  const AppLifecyclePage({super.key});

  @override
  State<AppLifecyclePage> createState() => _AppLifecyclePageState();
}

class _AppLifecyclePageState extends State<AppLifecyclePage> {
  late final AppLifecycleListener _listener;

  @override
  void initState() {
    super.initState();

    _listener = AppLifecycleListener(
      // Handle the onExitRequested callback
      onExitRequested: _onExitRequested,
    );
  }

  @override
  void dispose() {
    _listener.dispose();

    super.dispose();
  }

  // Ask the user if they want to exit the app. If the user
  // cancels the exit, return AppExitResponse.cancel. Otherwise,
  // return AppExitResponse.exit.
  Future<AppExitResponse> _onExitRequested() async {
    final response = await showDialog<AppExitResponse>(
      context: context,
      barrierDismissible: false,
      builder: (context) => AlertDialog.adaptive(
        title: const Text('Are you sure you want to quit this app?'),
        content: const Text('All unsaved progress will be lost.'),
        actions: [
          TextButton(
            child: const Text('Cancel'),
            onPressed: () {
              Navigator.of(context).pop(AppExitResponse.cancel);
            },
          ),
          TextButton(
            child: const Text('Ok'),
            onPressed: () {
              Navigator.of(context).pop(AppExitResponse.exit);
            },
          ),
        ],
      ),
    );

    return response ?? AppExitResponse.exit;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('App Lifecycle Demo'),
      ),
      body: Center(
        child: Text(
          '						
Источник: https://habr.com/ru/articles/759628/


Интересные статьи

Интересные статьи

Hola, Amigos! На связи Саша Чаплыгин, Flutter-dev Amiga и Тимур Моисеев, Teamlead Flutter Amiga. Буквально пару недель назад вышла новая версия Flutter 3.10. Из этой статьи вы узнаете об изменени...
Исследование Роберта Сэнсона может проложить путь к производству электромобилей без редкоземельных магнитов. Подробности — к старту нашего флагманского курса по Data Science.
Микроскоп — надежный и нужный инструмент не только для ученых, медиков, но и представителей других специальностей. Это еще и отличный способ познакомить ребенка с невидимыми тайнами и...
Привет, Хабр! Сегодня мы поговорим немного о DevOps и самоорганизации.Мы начнем с фразы, с которой не соглашается добрая половина разработчиков в индустрии: "каждый разра...
Власть в блоге Технократии переходит андроид-разработчикам. Владислав Титов рассказывает про то, как добиться непрерывающегося UI при смене локализации. Чи...