Flutter中StatefullWidget的生命周期

从事原生开发的人,对生命周期并不陌生。很多交互都离不开生命周期,比如页面每次可见时开启定时器,不可见时停止定时器。本篇文章不做深入的流程分析,算是一篇总结性的文章,主要介绍生命周期的方法以及如何使用。
生命周期的图示如下

bba88ebb44b7fdd6735f3ddb41106784.png

可以看到,State 的生命周期可以分为 3 个阶段:创建(插入视图树)、更新(在视图树中存在)、销毁(从视图树中移除)。

创建

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

  • 构造方法是 State 生命周期的起点,Flutter 会通过调用 StatefulWidget.createState() 来创建一个 State。我们可以通过构造方法,来接收父 Widget 传递的初始化 UI 配置数据。这些配置数据,决定了 Widget 最初的呈现效果。
  • initState,会在 State 对象被插入视图树的时候调用。这个函数在 State 的生命周期中只会被调用一次,所以我们可以在这里做一些初始化工作,比如为状态变量设定默认值。
  • **didChangeDependencies** 则用来专门处理 State 对象依赖关系变化,会在 initState() 调用结束后,被 Flutter 调用。
  • build,作用是构建视图。经过以上步骤,Framework 认为 State 已经准备好了,于是调用 build。我们需要在这个函数中,根据父 Widget 传递过来的初始化配置数据,以及 State 的当前状态,创建一个 Widget 然后返回。

更新

Widget 的状态更新,主要由 3 个方法触发:setStatedidchangeDependenciesdidUpdateWidget

  • **setState**:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!”
  • didChangeDependencies:State 对象的依赖关系发生变化后,Flutter 会回调这个方法,随后触发组件构建。哪些情况下 State 对象的依赖关系会发生变化呢?这个“依赖”指的就是子widget是否使用了父widget中InheritedWidget的数据!如果使用了,则代表子widget依赖有依赖InheritedWidget;如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget变化时来更新自身!比如当主题、locale(语言)等发生变化时,依赖其的子widget的didChangeDependencies方法将会被调用。
  • didUpdateWidget:当 Widget 的配置发生变化时,比如,父 Widget 触发重建(即父 Widget 的状态发生变化时),热重载时,系统会调用这个函数。一旦这三个方法被调用,Flutter 随后就会销毁老 Widget,并调用 build 方法重建 Widget。

想要获取或者监听APP在前台或者后台可以使用WidgetsBindingObserver,这个类中有如下这些回调

abstract class WidgetsBindingObserver {
  //页面pop
  Future<bool> didPopRoute() => Future<bool>.value(false);
  //页面push
  Future<bool> didPushRoute(String route) => Future<bool>.value(false);
  //系统窗口相关改变回调,如旋转
  void didChangeMetrics() { }
  //文本缩放系数变化
  void didChangeTextScaleFactor() { }
  //系统亮度变化
  void didChangePlatformBrightness() { }
  //本地化语言变化
  void didChangeLocales(List<Locale> locale) { }
  //App生命周期变化
  void didChangeAppLifecycleState(AppLifecycleState state) { }
  //内存警告回调
  void didHaveMemoryPressure() { }
  //Accessibility相关特性回调
  void didChangeAccessibilityFeatures() {}
}

如果只监听前后台的话,可以通过didChangeAppLifecycleState来进行,这个state主要有四种状态

  • resumed:可见的,并能响应用户的输入。
  • inactive:处在不活动状态,无法处理用户响应。
  • paused:不可见并不能响应用户的输入,但是在后台继续活动中。
  • detached: 它可以是在引擎首次初始化时附加视图的过程中,也可以是在视图由于导航器而被破坏之后

通常会在initState方法中添加监听,在dispose方法中解除监听,示例代码如下

class _MyHomePageState extends State<MyHomePage>  with WidgetsBindingObserver{
  ...
  @override
  void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this);//注册监听器
  }
  @override
  void dispose(){
  super.dispose();
  WidgetsBinding.instance.removeObserver(this);//移除监听器
  }
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
  print("$state");
  if (state == AppLifecycleState.resumed) {
  //do sth
  }
  }
}

如果想要实现类似Android中的View.post功能,可以使用

WidgetsBinding.instance.addPostFrameCallback((_){

print("单次Frame绘制回调");//只回调一次

});

如果有多个页面注册了前后台监听,比如A打开了B且A没关闭。A与B都注册了监听。这时候如果退到后台这两个页面都会受到通知

image.png

如果从后台回来

image11.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY5botos' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片