Flutter 小技巧之 3.13 全新生命周期 AppLifecycleListener

news2024/11/14 21:21:07

Flutter 3.13 在 Framework 里添加了 AppLifecycleListener 用于监听应用生命周期变化,并响应退出应用的请求等支持,那它有什么特殊之处?和老的相比又有什么不同?

简单说,在 Flutter 3.13 之前,我们一般都是用 WidgetsBindingObserverdidChangeAppLifecycleState 来实现生命周期的监听,只是 didChangeAppLifecycleState 方法比较「粗暴」,直接返回 AppLifecycleState 让用户自己处理,使用的时候需要把整个 WidgetsBindingObserver 通过 mixin 引入。

AppLifecycleListener 则是在 WidgetsBindingObserver.didChangeAppLifecycleState 的基础上进行了封装,再配合当前 lifecycleState 形成更完整的生命周期链条,对于开发者来说就是使用更方便,并且 API 相应更直观。

首先 AppLifecycleListener 是一个完整的类,所以使用它无需使用 mixin ,你只需要在使用的地方创建一个 AppLifecycleListener 对象即可。

late final AppLifecycleListener _listener;
late AppLifecycleState? _state;

void initState() {
  super.initState();
  _state = SchedulerBinding.instance.lifecycleState;
  _listener = AppLifecycleListener(
    onShow: () => _handleTransition('show'),
    onResume: () => _handleTransition('resume'),
    onHide: () => _handleTransition('hide'),
    onInactive: () => _handleTransition('inactive'),
    onPause: () => _handleTransition('pause'),
    onDetach: () => _handleTransition('detach'),
    onRestart: () => _handleTransition('restart'),
    // This fires for each state change. Callbacks above fire only for
    // specific state transitions.
    onStateChange: _handleStateChange,
  );
}
void _handleTransition(String name) {
  print("########################## main $name");
}

其次,AppLifecycleListener 根据 AppLifecycleState 区分好了所有 Callback 调用,调用编排更加直观。

最后,AppLifecycleListener 可以更方便去判断和记录整个生命周期的链条变化,因为它已经帮你封装好回调方法,例如:

  • inactiveresumed 调用的是 onResume
  • detachedresumed 调用的是 onStart

现在通过 AppLifecycleListener 的回调,我们可以更方便和直观的感知到整个生命周期变化的链条,并且 3.13 正式版中还引入了一个全新的状态 : 「hidden」,当然它其实在 Android/iOS 上是不工作的。

因为 hidden 这个概念在移动 App 上并不实际存在,例如它定义在这里只是为了对齐统一所有状态。

虽然在移动 App 平台虽然没有 hidden 这个状态,但是例如你在 Android 平台使用 AppLifecycleListener ,却还是可以收到 hidden 的状态回调,为什么会这样我们后面解释。

首先我们简单看下 AppLifecycleState 的几个状态:

detached

App 可能还存有 Flutter Engine ,但是视图并不存在,例如没有 FlutterView ,Flutter 初始化之前所处的默认状态。

也就是其实没有视图的情况下 Engine 还可以运行,一般来说这个状态仅在 iOS 和 Android 上才有,尽管所有平台上它是开始运行之前的默认状态,一般不严谨要求的情况下,可以简单用于退出 App 的状态监听。

resumed

表示 App 处于具有输入焦点且可见的正在运行的状态。

例如在 iOS 和 macOS 上对应于在前台活动状态。

Android 上无特殊情况对应 onResume 状态,但是其实和 Activity.onWindowFocusChanged 有关系。

例如当存在多 Activity 时:

  • 只有 Focus 为 true 的 Activity ,进入 onResume 才会是 resumed
  • 其他 Focus 为 false 的 Activity,进入 onResume 会是 inactive

只要还是看 Activity.onWindowFocusChanged 回调里是否 Foucs,只是默认情况下 Flutter 只有单 Activity ,所以才说无特殊情况对应 onResume 状态。

inactive

App 至少一个视图是可见的,但没有一个视图具 Focus。

  • 在非 Web 桌面平台上,这对应于不在前台但仍具有可见窗口的应用。
  • 在 Web ,这对应没有焦点的窗口或 tab 里运行的应用。
  • 在 iOS 和 macOS 上,对应在前台非活动状态下运行的 Flutter 视图,例如出现电话、生物认证、应用切换、控制中心时。
  • 在 Android 上,这对应 Activity.onPause 已经被调用或 onResume 时没有 Focus 的状态。(分屏、被遮挡、画中画)

在 Android 和 iOS 上, inactive 可以认为它们马上会进入 hidden 和 paused 状态。

paused

App 当前对用户不可见,并且不响应用户行为。

当应用程序处于这个状态时,Engine 不会调用 PlatformDispatcher.onBeginFramePlatformDispatcher.onDrawFrame 回调。

仅在 iOS 和 Android 上进入此状态。

hidden

App 的所有视图都被隐藏。

  • 在 iOS 和 Android 上说明马上要进入 paused。

  • 在 PC 上说明最小化或者不再可见的桌面上。

  • 在 Web 上说明在不可见的窗口或选项卡中。

所以从上面可以看到,其实不同平台的生命周期还是存在差异的,而 AppLifecycleState 的作用就是屏蔽这些差异,并且由于历史原因,目前 Flutter 的状态名称并不与所平台上的状态名称一一对应,例如 :

在 Android 上,当系统调用 Activity.onPause 时,Flutter 会进入 inactive 状态;但是当 Android 调用 Activity.onStop,Flutter会进入 paused 状态。

当然,如果 App 被任务管理器、crash、kill signal 等场景销毁时,用户是无法收到任何回调通知的。

那么这时候,你再回过头来看 hidden ,就会知道为什么它在 Android 和 iOS 上并没有实际意义,因为它是为了 PC 端(最小化/不可见)而存在,但是如果你通过 AppLifecycleListener 进行监听,你会发现其实是可以收到 hidden 的回调,例如在 Android 和 iOS 上 :

  • 前台到后台: inactive - hide - pause

  • 后台回前台:restart - show - resume

明明在原生 Android 和 iOS 上并没有 hidden ,那为什么 Dart 里又会触发呢?

这是因为 Flutter 在 Framework 为了保证 Dart 层面生命周期的一致性,会对生命周期调用进去「补全」。

例如在退到后台时,native 端只发送了 inactivepause 两个状态,但是收到 pause 时,在 _generateStateTransitions 方法里,会根据 pauseAppLifecycleState 里的位置(pause 和 inactive 之间还有 hidden) ,在代码里「手动」加入 hidden 从而触发 onHide 调用。

所以,在 Android 和 iOS 端使用 AppLifecycleState 时,我们一般不要去依赖 onHide 回调,因为本质上它并不适用于移动端的生命周期。

最后,AppLifecycleState 还提供了 onExitRequested 方法,但是它并不支持类似 Android 的 back 返回拦截场景,而是需要通过 ServicesBinding.instance.exitApplication(AppExitType exitType) 触发的退出请求,才可以被 onExitRequested 拦截,前提是调用时传入了 AppExitType.cancelable

也就是 ServicesBinding.instance.exitApplication(AppExitType.cancelable); 这样的调用才会触发 onExitRequested ,另外目前 System.exitApplication 的响应只在 PC 端实现,移动端不支持。


void initState() {
  super.initState();
  _listener = AppLifecycleListener(
    onExitRequested: _handleExitRequest,
  );
}

Future<AppExitResponse> _handleExitRequest() async {
  var result = await showDialog(
      context: context,
      builder: (context) => AlertDialog.adaptive(
            title: const Text('Exit'),
            content: const Text('Exit'),
            actions: [
              TextButton(
                child: const Text('No'),
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
              ),
              TextButton(
                child: const Text('Yes'),
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
              ),
            ],
          ));
  final AppExitResponse response =
      result ? AppExitResponse.exit : AppExitResponse.cancel;
  return response;
}

最后做个总结:

  • AppLifecycleListener 的好处就是不用 mixin ,并且通过回调可以判断生命周期链条。
  • AppLifecycleState 的状态和命名与原生端并不一定对应。
  • Flutter 在单页面和多页面下可能会出现不同的状态相应。
  • hidden 在 Android 和 iOS 端并不存在,它仅仅是为了统一而手动插入的中间过程。
  • onExitRequested 只作用于 PC 端。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/908170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计网第三章(数据链路层)(五)

目录 一、以太网交换机自学习和转发帧的过程 1.两层交换机和三层交换机 2.以太网交换机的基本原理 3.具体实现过程 一、以太网交换机自学习和转发帧的过程 1.两层交换机和三层交换机 大家可能注意到平常做题时有叫两层交换机&#xff0c;或者三层交换机的。 两层交换机就…

为什么需要websocket?

一、为什么需要websocket&#xff1f; 前端和后端的交互模式最常见的就是前端发数据请求&#xff0c;从后端拿到数据后展示到页面中。如果前端不做操作&#xff0c;后端不能主动向前端推送数据&#xff0c;这也是http协议的缺陷。 因此&#xff0c;一种新的通信协议应运而生---…

使用kabeja库解析DXF格式文件

DXF格式是一种开源的CAD文件格式&#xff0c;如何实现Java代码对齐的解析&#xff0c;在网上找了很久&#xff0c;也没有找到非常成熟的库。很奇怪&#xff0c;开源的格式&#xff0c;正常应该会有很多的库来支持。只找到了一个kabeja库&#xff0c;最新版本还是2008年出的0.4版…

GTK3实现自定义列表

使用gtk,如果想自己定义列表,思路可以将每个列表项作为一个hbox,整个列表是一个vbox。通过对容器动态的添加删除,实现列表操作,同时添加任何自己所需要的控件。 下面的例子是实现一个显示图片、按钮和进度条的列表,并且进行上移下移,具有添加和删除列表项功能但没有演示…

网站巡查与SEO:爱校对如何确保内容的最佳质量?

随着互联网的飞速发展&#xff0c;企业和个人正在寻找优化他们网站内容的最佳方式。在这个数字化时代&#xff0c;网站巡查和SEO已成为维持网站高度相关性和可见性的关键。此时&#xff0c;工具如“爱校对”不仅帮助检查文本的质量&#xff0c;还确保内容对搜索引擎优化&#x…

STM32使用定时器实现微秒(us)级延时

STM32使用定时器实现微秒&#xff08;us&#xff09;级延时 引言前期准备介绍系统时钟定时器时钟 项目项目介绍STM32CubeMX程序 引言 目前开发STM32普遍使用HAL库&#xff0c;但 HAL 库封装的延时函数目前仅支持 ms 级别的延时&#xff0c;日常很多情况下会用到 us 延时&#…

IC封装——从基本概念到TSV

一、IC封装 在之前文章中有大致提过封装&#xff0c;这里展开讲讲 芯片生产流程_沧海一升的博客-CSDN博客每个半导体产品的制造都需要数百个工艺&#xff0c;泛林集团将整个制造过程分为八个步骤&#xff1a;晶圆加工-氧化-光刻-刻蚀-薄膜沉积-互连-测试-封装。_芯片生产流程h…

spring异步框架使用教程

背景 在需求开发过程中&#xff0c;为了提升效率&#xff0c;很容易就会遇到需要使用多线程的场景。这个时候一般都会选择建一个线程池去专门用来进行某一类动作&#xff0c;这种任务到来的时候往往伴随着大量的线程被创建调用。而还有另外一种场景是整个任务的执行耗时比较长…

ElasticSearch 7.4学习记录(DSL语法)

上文和大家一起初次了解了很多ES相关的基础知识&#xff0c;本文的内容将会是实际企业中所需要的吗&#xff0c;也是我们需要熟练应用的内容。 面对ES&#xff0c;我们最多使用的就是查询&#xff0c;当我负责这个业务时&#xff0c;现不需要我去考虑如何创建索引&#xff0c;添…

ubuntu18.04安装keil5(踩坑)看完再享用,别直接上手

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装winewine的总结 二、安装Keil5总结 前言 切记看完再享用&#xff0c;别直接上手&#xff0c;不然安装的时候会和我一样踩坑的&#xff08;走了很多弯路…

Unity之用Transform 数组加多个空物体-->简单地控制物体按照指定路线自动行驶

文章目录 **原理解释**&#xff1a;**带注释的代码**&#xff1a;实际运用 当你需要实现物体按照指定路线行驶时&#xff0c;你可以通过以下步骤来实现&#xff1a; 原理解释&#xff1a; 路径点&#xff1a;你需要定义一系列路径点&#xff0c;这些点将构成物体行驶的路线。每…

[软件工具]精灵标注助手目标检测数据集格式转VOC或者yolo

有时候我们拿到一个数据集发现是xml文件格式如下&#xff1a; <?xml version"1.0" ?> <doc><path>C:\Users\Administrator\Desktop\test\000000000074.jpg</path><outputs><object><item><name>dog</name>…

纷享销客连接型CRM助力中国企业全球业务增长

近年来&#xff0c;中国企业出海热度越来越高&#xff0c;中国企业出海之路也越走越宽&#xff0c;全球化步伐明显加速。2023年&#xff0c;中国企业业务出海正进入快车道和分水岭阶段&#xff0c;中国也正在从一个世界工厂变成全球资源的整合者。 0 中国企业出海&#xff0c…

精简体积的OLED 基础驱动库 - OLED_BASIC

打算用一个存储空间不大的Arduino 芯片做点简单的文字和图形显示&#xff0c;屏幕芯片SSD1316&#xff0c;感觉u8g2 占用还是太大&#xff0c;想裁剪别人的现成代码又感觉无从下手&#xff0c;所以就基本上重写了一个OLED 显示库&#xff0c;仓库地址&#xff1a;gitee.com/etb…

SQL助你面大厂(Join家族介绍)

在学习SQL时候&#xff0c;在多表查询的时候你肯定使用过Join&#xff0c;无非就是把两表联合在一起进行多表查询&#xff0c;但是你是真的了解它们的用法么&#xff1f; Join家族一般有left Join、Rigth Join、Inner Join、Left Semi Join、Left Anti Join、Full Join为主 C…

补充1 MATLAB_GUI_修改普通按钮(PushButton)的参数创建一个长按回调按钮

目录 一、实例效果二、补充的知识点&#xff08;两种回调函数&#xff09;三、步骤  1. 先建一个空白的GUI。  2.在GUI Figure 上添加一个按钮&#xff08;PushButton&#xff09;组件&#xff0c;并设置其属性&#xff0c;例如位置、大小和文本等。  3.CtrS保存一下GUI。…

强推9个研究生必备的免费论文下载网站

一、文献党下载器 文献党下载器把庞大的中外文献数据库资源集成在一个平台&#xff0c;就是把大量的中外数据库资源整合在一个站&#xff08;目前文献资源量名列前茅&#xff09;。不论是中文还是外文文献&#xff0c;不论是哪种文献类型&#xff0c;不论是哪个学科领域该网站…

<kernel>kernel 6.4 USB-之-hub_port_connect()分析

&#xff1c;kernel&#xff1e;kernel 6.4 USB-之-hub_port_connect()分析 kernel 6.4 USB系列文章如下&#xff1a; &#xff1c;kernel&#xff1e;kernel 6.4 USB-之-hub_event()分析 &#xff1c;kernel&#xff1e;kernel 6.4 USB-之-port_event()分析 &#xff1c;kern…

全球机器传感器市场价值约为142亿美元,预计将以超过7.5%的增长率增长

机器传感器是一类用于检测、测量和感知机器环境中物理量、化学量或其他特定参数的设备。这些传感器将实际的物理现象转化为电信号或数字信号&#xff0c;以便计算机或控制系统进行处理、分析和控制。机器传感器在工业、自动化、物联网、机器人、汽车等领域有广泛应用。 根据阿…

部门来了个新同事,听说是00后,上来一顿操作给我看呆了...

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&#x…