Flutter 封装:最佳实践 —— AppLifecycleState 状态监听封装

一、需求来源

项目中多页面需要同时监听 AppLifecycleState 根据状态实现不同的业务逻辑;尝试多种实现,使用起来比较麻烦,为了开发效率,随封装一个。代码不复杂,核心在于极简的封装方法。

效果如下:

csharp 复制代码
[log] 2024-01-20 11:04:36.473511 MyHomePage onInactive
[log] 2024-01-20 11:04:36.476352 AppLifecycleStateObserverDemo onInactive
[log] 2024-01-20 11:04:37.189494 MyHomePage onPause
[log] 2024-01-20 11:04:37.190003 AppLifecycleStateObserverDemo onPause
[log] 2024-01-20 11:04:41.896665 MyHomePage onInactive
[log] 2024-01-20 11:04:41.896964 AppLifecycleStateObserverDemo onInactive
[log] 2024-01-20 11:04:42.177396 MyHomePage onResume
[log] 2024-01-20 11:04:42.178090 AppLifecycleStateObserverDemo onResume

// MyHomePage 为主页面;
// AppLifecycleStateObserverDemo 为特定业务界面;

二、使用示例

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_templet_project/util/AppLifecycleObserver.dart';
import 'package:flutter_templet_project/util/debug_log.dart';

class AppLifecycleStateObserverDemo extends StatefulWidget {

  AppLifecycleStateObserverDemo({
    super.key, 
    this.title
  });

  final String? title;

  @override
  State<AppLifecycleStateObserverDemo> createState() => _AppLifecycleStateObserverDemoState();
}

class _AppLifecycleStateObserverDemoState extends State<AppLifecycleStateObserverDemo> with
    WidgetsBindingObserver,
    AppLifecycleObserverMixin {

  final _scrollController = ScrollController();


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title ?? "$widget"),
        actions: ['done',].map((e) => TextButton(
          child: Text(e,
            style: TextStyle(color: Colors.white),
          ),
          onPressed: () => debugPrint(e),)
        ).toList(),
      ),
      body: buildBody(),
    );
  }

  buildBody() {
    return Scrollbar(
      controller: _scrollController,
      child: SingleChildScrollView(
        controller: _scrollController,
        child: Column(
          children: [
            Text("$widget"),
          ],
        ),
      ),
    );
  }

  /*************** AppLifecycleObserverMixin ***************/
  
  @override
  Future<void> onResume() async {
    // TODO: implement onResume
    DDLog("$widget onResume");
  }

  @override
  Future<void> onInactive() async {
    // TODO: implement onInactive
    DDLog("$widget onInactive");
  }

  @override
  Future<void> onPause() async {
    // TODO: implement onPause
    DDLog("$widget onPause");
  }

  @override
  Future<void> onDetached() async {
    // TODO: implement onDetached
    DDLog("$widget onDetached");
  }
}

三、源码

1、AppLifecycleObserver 源码

dart 复制代码
/// app 前后台生命周期函数监听
class AppLifecycleObserver extends WidgetsBindingObserver{

  AppLifecycleObserver({
    required this.onResume,
    required this.onInactive,
    required this.onPause,
    required this.onDetached,
    this.data,
  });

  final AsyncCallback onResume;
  final AsyncCallback onInactive;
  final AsyncCallback onPause;
  final AsyncCallback onDetached;
  final dynamic data;

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    // DDLog('${Get.currentRoute} APP状态监听:$state, ${data ?? ""}');

    switch (state) {
      case AppLifecycleState.resumed:
        onResume();
        break;
      case AppLifecycleState.inactive:
        onInactive();
        break;
      case AppLifecycleState.paused:
        onPause();
        break;
      case AppLifecycleState.detached:
        onDetached();
        break;
    }
  }
}

2、AppLifecycleObserverMixin 源码

dart 复制代码
/// app 前后台生命周期函数混入封装
mixin AppLifecycleObserverMixin<T extends StatefulWidget> on State<T>, WidgetsBindingObserver{
  late final _lifecycleEvent = AppLifecycleObserver(
    onResume: onResume,
    onInactive: onInactive,
    onPause: onPause,
    onDetached: onDetached,
  );

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(_lifecycleEvent);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(_lifecycleEvent);
    super.dispose();
  }

  Future<void> onResume() async {
    throw UnimplementedError("❌: $this 未实现 onResume");
  }

  Future<void> onInactive() async {
    throw UnimplementedError("❌: $this 未实现 onInactive");
  }

  Future<void> onPause() async {
    throw UnimplementedError("❌: $this 未实现 onPause");
  }

  Future<void> onDetached() async {
    throw UnimplementedError("❌: $this 未实现 onDetached");
  }

}

四、总结

1、使用 AppLifecycleObserverMixin 需要同时遵循 WidgetsBindingObserver
scala 复制代码
class _AppLifecycleStateObserverDemoState extends State<AppLifecycleStateObserverDemo> with
    WidgetsBindingObserver,
    AppLifecycleObserverMixin {
2、AppLifecycleObserverMixin 生命周期方法是一组,即使不使用也要全部实现(考虑到未来排查错误);如果未实现会日志报错,提示到具体页面;

github

相关推荐
道不尽世间的沧桑15 分钟前
第9篇:插槽(Slots)的使用
前端·javascript·vue.js
bin915319 分钟前
DeepSeek 助力 Vue 开发:打造丝滑的滑块(Slider)
前端·javascript·vue.js·前端框架·ecmascript·deepseek
uhakadotcom36 分钟前
最新发布的Tailwind CSS v4.0提供了什么新能力?
前端
GISer_Jing1 小时前
Node.js中如何修改全局变量的几种方式
前端·javascript·node.js
秋意钟1 小时前
Element UI日期选择器默认显示1970年解决方案
前端·javascript·vue.js·elementui
bramble1 小时前
Windows使用Trae全程提问来创建一个彩色贪吃蛇游戏,可以设置速度并查看游戏记录。
前端·程序员·trae
我命由我123452 小时前
微信小程序 - 自定义实现分页功能
前端·微信小程序·小程序·前端框架·html·html5·js
程序员黄同学2 小时前
请谈谈 Vue 中的 key 属性的重要性,如何确保列表项的唯一标识?
前端·javascript·vue.js
繁依Fanyi3 小时前
巧妙实现右键菜单功能,提升用户操作体验
开发语言·前端·javascript·vue.js·uni-app·harmonyos
前端御书房3 小时前
前端防重复请求终极方案:从Loading地狱到精准拦截的架构升级
前端·javascript