Flutter 3.13 在 Framework 里添加了 AppLifecycleListener 用于监听运用生命周期改变,并呼应退出运用的恳求等支持,那它有什么特殊之处?和老的相比又有什么不同?
简单说,在 Flutter 3.13 之前,咱们一般都是用 WidgetsBindingObserver 的 didChangeAppLifecycleState 来实现生命周期的监听,仅仅 didChangeAppLifecycleState 办法比较「粗暴」,直接回来 AppLifecycleState 让用户自己处理,运用的时分需要把整个 WidgetsBindingObserver 经过 mixin 引入。
而 AppLifecycleListener 则是在 WidgetsBindingObserver.didChangeAppLifecycleState 的基础上进行了封装,再配合当时 lifecycleState 构成更完好的生命周期链条,对于开发者来说便是运用更便利,而且 API 相应更直观。
首要 AppLifecycleListener 是一个完好的类,所以运用它无需运用 mixin ,你只需要在运用的地方创建一个 AppLifecycleListener 目标即可。
latefinalAppLifecycleListener_listener;
lateAppLifecycleState?_state;
@override
voidinitState() {
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(Stringname) {
print("########################## main$name");
}
其次,AppLifecycleListener 依据 AppLifecycleState 区分好了一切 Callback 调用,调用编排更加直观。
最后,AppLifecycleListener 能够更便利去判别和记载整个生命周期的链条改变,由于它现已帮你封装好回调办法,例如:
- 从
inactive到resumed调用的是onResume - 从
detached到resumed调用的是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.onBeginFrame 和PlatformDispatcher.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 端只发送了 inactive 和 pause 两个状况,可是收到 pause 时,在 _generateStateTransitions 办法里,会依据 pause 在 AppLifecycleState 里的方位(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 端实现,移动端不支持。
@override
voidinitState() {
super.initState();
_listener=AppLifecycleListener(
onExitRequested:_handleExitRequest,
);
}
Future<AppExitResponse>_handleExitRequest()async{
varresult=awaitshowDialog(
context:context,
builder: (context)=>AlertDialog.adaptive(
title:constText('Exit'),
content:constText('Exit'),
actions: [
TextButton(
child:constText('No'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
TextButton(
child:constText('Yes'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
],
));
finalAppExitResponseresponse=
result?AppExitResponse.exit:AppExitResponse.cancel;
returnresponse;
}
最后做个总结:
-
AppLifecycleListener的优点便是不必 mixin ,而且经过回调能够判别生命周期链条。 -
AppLifecycleState的状况和命名与原生端并不一定对应。 - Flutter 在单页面和多页面下或许会呈现不同的状况相应。
- hidden 在 Android 和 iOS 端并不存在,它仅仅是为了一致而手动刺进的中心过程。
-
onExitRequested只效果于 PC 端。









