Cách lắng nghe sự kiện vòng đời trong Flutter từ 3.13 trở đi.

Trong Flutter, có một số sự kiện trong vòng đời mà bạn có thể nghe để xử lý các trạng thái khác nhau của ứng dụng, nhưng hôm nay, chúng ta sẽ thảo luận về các sự kiện didChangeAppLifecycleState trước và sau phiên bản Flutter 3.13.

Trạng thái vòng đời trong ứng dụng Flutter là gì?

Sự kiện này được kích hoạt bất cứ khi nào trạng thái vòng đời của ứng dụng thay đổi. Các trạng thái có thể được tiếp tục, không hoạt động, tạm dừng, tách rời và ẩn. Bạn có thể nghe sự kiện này bằng cách sử dụng mixin WidgetsBindingObserver.

  • resumed: Trên tất cả các nền tảng, trạng thái này cho biết ứng dụng đang ở trạng thái chế độ chạy mặc định cho một ứng dụng đang chạy có tiêu điểm đầu vào và dễ thấy.
  • detached: Ứng dụng này vẫn được lưu trữ bởi công cụ Flutter nhưng được tách ra khỏi bất kỳ lượt xem máy chủ nào.
  • inactive: Ít nhất một chế độ xem của ứng dụng được hiển thị nhưng không có chế độ xem nào có đầu vào tập trung. Ứng dụng vẫn chạy bình thường.
  • hidden: Tất cả các chế độ xem của một ứng dụng đều bị ẩn vì ứng dụng đó sắp bị tạm dừng (trên iOS và Android) hoặc vì nó đã bị thu nhỏ hoặc được đặt trên một màn hình không còn hiển thị (trên màn hình không có web) hoặc đang chạy trong một cửa sổ hoặc tab không còn hiển thị (trên web).
  • paused: Ứng dụng hiện không hiển thị với người dùng và không phản hồi tới đầu vào của người dùng.

Lắng nghe sự kiện vòng đời trước phiên bản 3.13

Trong các phiên bản Flutter trước 3.13, bạn có thể xử lý các sự kiện trong vòng đời ứng dụng bằng cách sử dụng mixin WidgetsBindingObserver. Để thực hiện việc này, bạn sẽ bao gồm mixin WidgetsBindingObserver trong lớp State của mình và ghi đè phương thức didChangeAppLifecycleState. Trong phương pháp này, bạn có thể truy cập trạng thái hiện tại của ứng dụng (AppLifecycleState) và phản hồi tương ứng với các sự kiện khác nhau trong vòng đời ứng dụng.

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

  @override
  State<AppLifeCycleExample> createState() => _AppLifeCycleExampleState();
}

class _AppLifeCycleExampleState extends State<AppLifeCycleExample>
    with WidgetsBindingObserver {
  late final AppLifecycleListener listener;

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

    super.didChangeDependencies();
  }

  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 Placeholder();
  }
}

Lắng nghe sự kiện vòng đời sau phiên bản Flutter 3.13

Sau Flutter 3.13, chúng ta có thể nghe các sự kiện trong vòng đời ứng dụng bằng cách sử dụng lớp AppLifecycleListener mới.

Lớp AppLifecycleListener cung cấp một cách tiếp cận thuận tiện và thay thế để nghe các sự kiện trong vòng đời ứng dụng trong Flutter. Thay vì trực tiếp sử dụng mixin WidgetsBindingObserver, bạn có thể sử dụng lớp AppLifecycleListener để đơn giản hóa quy trình.

Để sử dụng AppLifecycleListener, hãy tạo một phiên bản của lớp và chuyển các lệnh gọi lại sự kiện mong muốn mà bạn muốn nghe. Điều này cho phép bạn dễ dàng xử lý các sự kiện trong vòng đời ứng dụng cụ thể mà không cần triển khai toàn bộ mixin WidgetsBindingObserver.

Bằng cách sử dụng AppLifecycleListener, bạn có thể hợp lý hóa mã của mình và làm cho mã dễ đọc và dễ bảo trì hơn vì bạn chỉ cần tập trung vào các sự kiện cụ thể mà bạn quan tâm.

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

  @override
  State<AppLifeCycleExample> createState() => _AppLifeCycleExampleState();
}

class _AppLifeCycleExampleState extends State<AppLifeCycleExample> {
  late final AppLifecycleListener listener;

  @override
  void initState() {
    super.initState();
    listener = AppLifecycleListener(onStateChange: _onStateChanged);
  }

  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
  void dispose() {
    listener.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Điểm khác biệt giữa chúng là gì?

Nhìn qua thì cách cũ và cách mới không có sự khác biệt. Để hiểu rõ hơn về lợi ích của AppLifecycleListener cùng xem sơ đồ vòng đời dưới đây.

Sơ đồ minh họa các trạng thái khác nhau của ứng dụng Flutter và các chuyển đổi có thể có giữa chúng.

Theo cách tiếp cận “cũ”, khi ghi đè phương thức didChangeAppLifecycleState, chúng ta chỉ có thể lắng nghe những thay đổi trạng thái cụ thể, chẳng hạn như khi ứng dụng chuyển sang trạng thái resumed. Tuy nhiên, bạn không thể nắm bắt được thông tin về sự chuyển đổi giữa các trạng thái. Ví dụ: bạn không thể xác định liệu ứng dụng đã chuyển sang trạng thái resumed từ inactive hay detached.

Với lớp AppLifecycleListener, giờ đây chúng ta có thể lắng nghe những chuyển đổi trạng thái này. Điều này có nghĩa là chúng ta có thể theo dõi cũng như phản hồi chuỗi trạng thái mà ứng dụng của bạn trải qua, hiểu biết toàn diện hơn về vòng đời của ứng dụng.

Bằng cách sử dụng lớp AppLifecycleListener, chúng ta có thể nắm bắt, xử lý hiệu quả quá trình chuyển đổi giữa các trạng thái, kiểm soát và tùy chỉnh hành vi ứng dụng một cách chính xác hơn.

Hủy việc thoát Ứng dụng bằng lớp AppLifecycleListener

Trong lớp AppLifecyleListener có một lệnh gọi lại onExitRequested. Lệnh này được sử dụng để hỏi ứng dụng xem liệu nó có cho phép thoát khỏi ứng dụng trong trường hợp lệnh thoát có thể bị hủy hay không.

Ví dụ,chúng ta thể được sử dụng cho các ứng dụng MacOS, khi người dùng cố gắng đóng ứng dụng khi có những thay đổi chưa được lưu.

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

  @override
  State<AppLifeCycleExample> createState() => _AppLifeCycleExampleState();
}

class _AppLifeCycleExampleState extends State<AppLifeCycleExample> {
  late final AppLifecycleListener listener;

  @override
  void initState() {
    super.initState();
    listener = AppLifecycleListener(
      onStateChange: _onStateChanged,
      onExitRequested: _onExitRequested,
    );
  }

  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
  void dispose() {
    listener.dispose();
    super.dispose();
  }

  Future<AppExitResponse> _onExitRequested() async {
    final response = await showDialog<AppExitResponse>(
      context: context,
      barrierDismissible: false,
      builder: (context) => AlertDialog.adaptive(
        title: const Text('Bạn có muốn thoát ứng dựng?'),
        content: const Text('Tất cả các tiến trình chưa được lưu sẽ bị mất.'),
        actions: [
          TextButton(
            child: const Text('Huỷ'),
            onPressed: () {
              Navigator.of(context).pop(AppExitResponse.cancel);
            },
          ),
          TextButton(
            child: const Text('Đồng ý'),
            onPressed: () {
              Navigator.of(context).pop(AppExitResponse.exit);
            },
          ),
        ],
      ),
    );

    return response ?? AppExitResponse.exit;
  }

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Cảm ơn mọi người đã đọc hết bài viết này!

0 Shares:
1 comment
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like