State 生命周期

State 的生命周期,指的是在用户参与的情况下,其关联的 Widget 所经历的,从创建到显示再到更新最后到停止,直至销毁等各个过程阶段。

State 的生命周期流程,如图 1 所示:

image.png

图 1 State 生命周期图

创建

State 初始化时会依次执行 :构造方法 -> initState -> didChangeDependencies -> build,随后完成页面渲染。

更新

Widget 的状态更新,主要由 3 个方法触发:setState、didchangeDependencies 与 didUpdateWidget。

销毁

组件销毁相对比较简单。比如组件被移除,或是页面销毁的时候,系统会调用 deactivate 和 dispose 这两个方法,来移除或销毁组件。

比较

image.png

App 生命周期

App 的生命周期,则定义了 App 从启动到退出的全过程。

在原生 Android、iOS 开发中,有时我们需要在对应的 App 生命周期事件中做相应处理,比如 App 从后台进入前台、从前台退到后台,或是在 UI 绘制完成后做一些处理。

这样的需求,在原生开发中,我们可以通过重写 Activity、ViewController 生命周期回调方法,或是注册应用程序的相关通知,来监听 App 的生命周期并做相应的处理。而在 Flutter 中,我们可以利用 WidgetsBindingObserver 类,来实现同样的需求。

  1. abstract class WidgetsBindingObserver {
  2. //页面pop
  3. Future<bool> didPopRoute() => Future<bool>.value(false);
  4. //页面push
  5. Future<bool> didPushRoute(String route) => Future<bool>.value(false);
  6. //系统窗口相关改变回调,如旋转
  7. void didChangeMetrics() { }
  8. //文本缩放系数变化
  9. void didChangeTextScaleFactor() { }
  10. //系统亮度变化
  11. void didChangePlatformBrightness() { }
  12. //本地化语言变化
  13. void didChangeLocales(List<Locale> locale) { }
  14. //App生命周期变化
  15. void didChangeAppLifecycleState(AppLifecycleState state) { }
  16. //内存警告回调
  17. void didHaveMemoryPressure() { }
  18. //Accessibility相关特性回调
  19. void didChangeAccessibilityFeatures() {}
  20. }

生命周期回调

didChangeAppLifecycleState 回调函数中,有一个参数类型为 AppLifecycleState 的枚举类,这个枚举类是 Flutter 对 App 生命周期状态的封装。它的常用状态包括 resumed、inactive、paused 这三个。

  • resumed:可见的,并能响应用户的输入。
  • inactive:处在不活动状态,无法处理用户响应。
  • paused:不可见并不能响应用户的输入,但是在后台继续活动中。

在下面的代码中,我们在 initState 时注册了监听器,在 didChangeAppLifecycleState 回调方法中打印了当前的 App 状态,最后在 dispose 时把监听器移除:

  1. class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver{//这里你可以再回顾下,第7篇文章“函数、类与运算符:Dart是如何处理信息的?”中关于Mixin的内容
  2. ...
  3. @override
  4. @mustCallSuper
  5. void initState() {
  6. super.initState();
  7. WidgetsBinding.instance.addObserver(this);//注册监听器
  8. }
  9. @override
  10. @mustCallSuper
  11. void dispose(){
  12. super.dispose();
  13. WidgetsBinding.instance.removeObserver(this);//移除监听器
  14. }
  15. @override
  16. void didChangeAppLifecycleState(AppLifecycleState state) async {
  17. print("$state");
  18. if (state == AppLifecycleState.resumed) {
  19. //do sth
  20. }
  21. }
  22. }

image.png

图 4 App 切换前后台状态变化示意

帧绘制回调

WidgetsBinding 提供了单次 Frame 绘制回调,以及实时 Frame 绘制回调两种机制,来分别满足不同的需求:

  • 单次 Frame 绘制回调,通过 addPostFrameCallback 实现。它会在当前 Frame 绘制完成后进行进行回调,并且只会回调一次,如果要再次监听则需要再设置一次。
  1. WidgetsBinding.instance.addPostFrameCallback((_){
  2. print("单次Frame绘制回调");//只回调一次
  3. });
  • 实时 Frame 绘制回调,则通过 addPersistentFrameCallback 实现。这个函数会在每次绘制 Frame 结束后进行回调,可以用做 FPS 监测。
  1. WidgetsBinding.instance.addPersistentFrameCallback((_){
  2. print("实时Frame绘制回调");//每帧都回调
  3. });