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

До 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(
          '????',
          style: Theme.of(context).textTheme.displayLarge,
        ),
      ),
    );
  }
}

Заключение

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

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


  1. andre-w2
    08.09.2023 07:16

    хорошая статья