美文网首页flutter
Flutter生命周期方法小技巧

Flutter生命周期方法小技巧

作者: 一笑轮回吧 | 来源:发表于2023-08-08 22:21 被阅读0次

    需求

    • A界面跳转到B界面,暂停A界面的音乐或者视频
    • B界面返回到A界面,播放A界面的音乐或者视频
    • A界面切换到后台,暂停A界面的音乐或者视频
    • A界面从后台切换到前台,播放A界面的音乐或者视频

    需求通过理解修改为:

    • 监听 StatefulWidget 的 onPause 方法
    • 监听 StatefulWidget 的 onResume 方法

    背景

    我们在使用Flutter开发界面时,很多时候是需要在当前界面切换到后台,或者说当前界面跳转到第二个页面时,需要处理一些事宜,比如说音乐暂停,视频暂停等等。但是 StatefulWidget 中的state并没有提供如Activity的onPause,onResume方法。所以我们需要自己搞一下,搞一下这2个方法出来,只要在这2个方法中处理便可以满足上面的需求。

    效果

    创建2个widget界面

    1、LifecyclePage 简称 A界面

    2、LifecycleNextPage 简称 B界面

    • 场景:A界面打开生命周期如下
    image.png
    • 场景2:A界面点击按钮跳转到B界面


      image.png
    • 场景3:B界面点击返回到A界面


      image.png
    • 场景4:A界面切换到后台


      image.png
    • 场景5:A界面后台切换到前台


      image.png
    • 场景6:A界面弹出对话框


      image.png
    • 场景7:关闭对话框


      image.png

    实现

    新增方法

    • onCreate
    • onResume
    • onPause
    • onDestroy

    onStart和onStop 这里就不做添加了,以上4个方法便可以完成需求。

    代码

    老样子,直接上代码,不讲原理,就是这么拽。

    • 创建NavigatorObserver
    import 'dart:async';
    
    import 'package:built_collection/built_collection.dart';
    import 'package:flutter/widgets.dart';
    
    class NavigationHistoryObserver extends NavigatorObserver {
      final List<Route<dynamic>?> _history = <Route<dynamic>?>[];
    
      BuiltList<Route<dynamic>> get history =>
          BuiltList<Route<dynamic>>.from(_history);
    
      Route<dynamic>? get top => _history.last;
    
      final List<Route<dynamic>?> _poppedRoutes = <Route<dynamic>?>[];
    
      BuiltList<Route<dynamic>> get poppedRoutes =>
          BuiltList<Route<dynamic>>.from(_poppedRoutes);
    
      Route<dynamic>? get next => _poppedRoutes.last;
    
      final StreamController _historyChangeStreamController =
          StreamController.broadcast();
    
      Stream<dynamic> get historyChangeStream =>
          _historyChangeStreamController.stream;
    
      static final NavigationHistoryObserver _singleton =
          NavigationHistoryObserver._internal();
    
      NavigationHistoryObserver._internal();
    
      factory NavigationHistoryObserver() {
        return _singleton;
      }
    
      @override
      void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
        _poppedRoutes.add(_history.last);
        _history.removeLast();
        _historyChangeStreamController.add(HistoryChange(
          action: NavigationStackAction.pop,
          newRoute: route,
          oldRoute: previousRoute,
        ));
      }
    
      @override
      void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
        _history.add(route);
        _poppedRoutes.remove(route);
        _historyChangeStreamController.add(HistoryChange(
          action: NavigationStackAction.push,
          newRoute: route,
          oldRoute: previousRoute,
        ));
      }
    
      @override
      void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
        _history.remove(route);
        _historyChangeStreamController.add(HistoryChange(
          action: NavigationStackAction.remove,
          newRoute: route,
          oldRoute: previousRoute,
        ));
      }
    
      @override
      void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
        int oldRouteIndex = _history.indexOf(oldRoute);
        _history.replaceRange(oldRouteIndex, oldRouteIndex + 1, [newRoute]);
        _historyChangeStreamController.add(HistoryChange(
          action: NavigationStackAction.replace,
          newRoute: newRoute,
          oldRoute: oldRoute,
        ));
      }
    }
    
    class HistoryChange {
      HistoryChange({this.action, this.newRoute, this.oldRoute});
    
      final NavigationStackAction? action;
      final Route<dynamic>? newRoute;
      final Route<dynamic>? oldRoute;
    }
    
    enum NavigationStackAction { push, pop, remove, replace }
    
    
    • 设置navigatorObservers
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Android小样',
          ...
          navigatorObservers: [NavigationHistoryObserver()],
          ...
        );
      }
    }
    
    • 创建PageState
    
    abstract class PageState<T extends StatefulWidget> extends State<T>
        with PageStateMixin {
      static final List<BuildContext> _contextList = [];
    
      @override
      void initState() {
        super.initState();
        onCreate();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          _addToContextList();
        });
      }
    
      @override
      void dispose() {
        onDestroy();
        _removeFromContextList();
        super.dispose();
      }
    
      @override
      void setState(VoidCallback fn) {
        if (mounted) {
          super.setState(fn);
        }
      }
    
      void _addToContextList() {
        if (!mounted) return;
        if (!_contextList.contains(context)) {
          _contextList.add(context);
        }
      }
    
      void _removeFromContextList() {
        if (_contextList.isEmpty) return;
        _contextList.removeWhere((element) => element == context);
      }
    }
    
    mixin PageStateMixin<T extends StatefulWidget> on State<T> {
      Route? _route;
    
      @override
      void didChangeDependencies() {
        _route ??= ModalRoute.of(context);
        if (_route != null) {
          RouteHistoryObserver.addResumeCallback(_route!, onResume);
          RouteHistoryObserver.addPauseCallback(_route!, onPause);
        }
        super.didChangeDependencies();
      }
    
      @override
      void dispose() {
        _route ??= ModalRoute.of(context);
        if (_route != null) {
          RouteHistoryObserver.removeResumeCallback(_route!, onResume);
          RouteHistoryObserver.removePauseCallback(_route!, onPause);
        }
        super.dispose();
      }
    
      void onCreate() {}
    
      void onResume() {}
    
      void onPause() {}
    
      void onDestroy() {}
    }
    
    class RouteHistoryObserver with WidgetsBindingObserver {
      static final Map<Route, Set<VoidCallback>> _resumeCallbacks = {};
      static final Map<Route, Set<VoidCallback>> _pauseCallbacks = {};
      static bool _initialized = false;
      static Route? _currTopRoute;
    
      static Route<dynamic>? get topRoute => _currTopRoute;
    
      static void init() {
        if (_initialized) return;
        _initialized = true;
        NavigationHistoryObserver()
            .historyChangeStream
            .listen(_appRouteHistoryChange);
        WidgetsBinding.instance.addObserver(RouteHistoryObserver());
      }
    
      @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        if (state == AppLifecycleState.resumed) {
          _appResume();
        } else if (state == AppLifecycleState.paused) {
          _appPause();
        }
      }
    
      static void _appRouteHistoryChange(dynamic historyChange) {
        if (NavigationHistoryObserver().history.isEmpty) return;
        var topRoute = NavigationHistoryObserver().top;
        if (historyChange.action == NavigationStackAction.push) {
          var preRoute = (historyChange as HistoryChange).oldRoute;
          var pauseCallbackList = _pauseCallbacks[preRoute];
          if (pauseCallbackList != null) {
            for (var callback in pauseCallbackList) {
              callback.call();
            }
          }
        } else if (historyChange.action == NavigationStackAction.pop) {
          var pauseCallbackList = _pauseCallbacks[_currTopRoute];
          if (pauseCallbackList != null) {
            for (var callback in pauseCallbackList) {
              callback.call();
            }
          }
        }
    
        if (topRoute != _currTopRoute) {
          _currTopRoute = topRoute;
          var resumeCallbackList = _resumeCallbacks[topRoute];
          if (resumeCallbackList == null) return;
          for (var callback in resumeCallbackList) {
            callback.call();
          }
        }
      }
    
      static void addResumeCallback(Route route, VoidCallback callback) {
        var callbackList = _resumeCallbacks[route];
        if (callbackList == null) {
          callbackList = {};
          _resumeCallbacks[route] = callbackList;
        }
        if (callbackList.add(callback) && _currTopRoute == route) {
          callback.call();
        }
      }
    
      static void removeResumeCallback(Route route, VoidCallback callback) {
        var callbackList = _resumeCallbacks[route];
        if (callbackList == null) return;
        callbackList.remove(callback);
      }
    
      static void addPauseCallback(Route route, VoidCallback callback) {
        var callbackList = _pauseCallbacks[route];
        if (callbackList == null) {
          callbackList = {};
          _pauseCallbacks[route] = callbackList;
        }
        callbackList.add(callback);
      }
    
      static void removePauseCallback(Route route, VoidCallback callback) {
        var callbackList = _pauseCallbacks[route];
        if (callbackList == null) return;
        callbackList.remove(callback);
      }
    
      static void _appResume() {
        if (_currTopRoute == null) return;
        var callbackList = _resumeCallbacks[_currTopRoute];
        if (callbackList == null) return;
        for (var callback in callbackList) {
          callback.call();
        }
      }
    
      static void _appPause() {
        if (_currTopRoute == null) return;
        var pauseCallbackList = _pauseCallbacks[_currTopRoute];
        if (pauseCallbackList == null) return;
        for (var callback in pauseCallbackList) {
          callback.call();
        }
      }
    }
    
    
    // 需要在app启动时初始化
    RouteHistoryObserver.init();
    
    
    • 创建2个界面Widget
    
    // 第一个界面
    class LifecyclePage extends StatefulWidget {
      const LifecyclePage({super.key});
    
      @override
      State<LifecyclePage> createState() => _LifecyclePageState();
    }
    
    class _LifecyclePageState extends PageState<LifecyclePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: XYAppBar(
            title: "Flutter生命周期",
            onBack: () {
              Navigator.pop(context);
            },
          ),
          body: SafeArea(
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      Navigator.push(context, MaterialPageRoute(
                        builder: (BuildContext context) {
                          return const LifecycleNextPage();
                        },
                      ));
                    },
                    child: const Text("跳转"),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      _showDialog(context);
                    },
                    child: const Text("弹出框"),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    
      void _showDialog(BuildContext context) {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: const Text('Dialog Title'),
              content: const Text('This is the content of the dialog.'),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop(); // Close the dialog
                  },
                  child: const Text('Close'),
                ),
              ],
            );
          },
        );
      }
    
      @override
      void onCreate() {
        super.onCreate();
        logger.d("LifecyclePage----onCreate");
      }
    
      @override
      void onPause() {
        super.onPause();
        logger.d("LifecyclePage----onPause");
      }
    
      @override
      void onResume() {
        super.onResume();
        logger.d("LifecyclePage----onResume");
      }
    
      @override
      void onDestroy() {
        logger.d("LifecyclePage----onDestroy");
        super.onDestroy();
      }
    }
    
    
    //第二个界面
    import 'package:flutter/material.dart';
    import 'package:flutter_xy/widgets/xy_app_bar.dart';
    import 'package:flutter_xy/xydemo/lifecycle/core/page_state.dart';
    
    import '../../utils/log_utils.dart';
    
    class LifecycleNextPage extends StatefulWidget {
      const LifecycleNextPage({super.key});
    
      @override
      State<LifecycleNextPage> createState() => _LifecycleNextPageState();
    }
    
    class _LifecycleNextPageState extends PageState<LifecycleNextPage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: XYAppBar(
            title: "Flutter生命周期第二页",
            onBack: () {
              Navigator.pop(context);
            },
          ),
          body: const SafeArea(
            child: Center(
              child: Text(
                "第二页",
                style: TextStyle(fontSize: 30),
              ),
            ),
          ),
        );
      }
    
      @override
      void onCreate() {
        super.onCreate();
        logger.d("LifecycleNextPage----onCreate");
      }
    
      @override
      void onPause() {
        super.onPause();
        logger.d("LifecycleNextPage----onPause");
      }
    
      @override
      void onResume() {
        super.onResume();
        logger.d("LifecycleNextPage----onResume");
      }
    
      @override
      void onDestroy() {
        logger.d("LifecycleNextPage----onDestroy");
        super.onDestroy();
      }
    }
    
    
    

    OK了,自己去测试测试吧。
    详情见Github:github.com/yixiaolunhui/flutter_xy

    相关文章

      网友评论

        本文标题:Flutter生命周期方法小技巧

        本文链接:https://www.haomeiwen.com/subject/ltlopdtx.html