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

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

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

AppLifecycleListener 则是在 WidgetsBindingObserver.didChangeAppLifecycleState 的基础上进行了封装,再配合当时 lifecycleState 构成更完好的生命周期链条,对于开发者来说便是运用更便利,而且 API 相应更直观。

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

首要 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 能够更便利去判别和记载整个生命周期的链条改变,由于它现已帮你封装好回调办法,例如:

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

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

现在经过 AppLifecycleListener 的回调,咱们能够更便利和直观的感知到整个生命周期改变的链条,而且 3.13 正式版中还引入了一个全新的状况 : 「hidden」,当然它其实在 Android/iOS 上是不作业的。

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

由于 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 状况。

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

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 上进入此状况。

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

hidden

App 的一切视图都被躲藏。

  • 在 iOS 和 Android 上阐明立刻要进入 paused。
  • 在 PC 上阐明最小化或者不再可见的桌面上。
  • 在 Web 上阐明在不行见的窗口或选项卡中。

所以从上面能够看到,其实不同渠道的生命周期仍是存在差异的,而 AppLifecycleState 的效果便是屏蔽这些差异,而且由于前史原因,现在 Flutter 的状况名称并不与所渠道上的状况名称一一对应,例如 :

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

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

当然,假如 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 调用。

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

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

所以,在 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 端。