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 端。