写点什么

flutter 系列之: 用来管理复杂状态的 State 详解

作者:程序那些事
  • 2022 年 6 月 06 日
  • 本文字数:2744 字

    阅读完需:约 9 分钟

flutter系列之:用来管理复杂状态的State详解

简介

Flutter 的基础是 widget,根据是否需要跟用户进行交互,widget 则可以分为 StatelessWidget 和 StatefulWidget。StatelessWidget 只能根据传入的状态进行简单的初始化 widget,如果要实现跟用户交互这种复杂的功能,则需要用到 StatefulWidget。


但是对于 StatefulWidget 本身来说,它并不存储任何状态,所有的状态都是存放在和 StatefulWidget 关联的 State 中的。


今天,让我们来探索一下 StatefulWidget 和 State 的关系。

StatefuWidget 和 State

StatefulWidget 的定义很简单,它是一个 abstract class,继承它只需要实现一个 createState 的方法:


abstract class StatefulWidget extends Widget {   const StatefulWidget({ Key? key }) : super(key: key);
@override StatefulElement createElement() => StatefulElement(this);
@protected @factory State createState(); }
复制代码


注意,这里的 createState 是一个工厂类方法。这就意味着一个 StatefulWidget 可以创建多个 State。


比如,如果从树中删除一个 StatefulWidget,稍后再次将其插入到树中,Flutter 将再次调用 StatefulWidget.createState 来创建一个新的 State 对象。


那么 State 中可以访问创建它的 StatefulWidget 吗?答案是肯定的。


在 State 中定义了一个 T 类型的 widget, 这个 T 是 StatefulWidget 的子类:


abstract class State<T extends StatefulWidget> with Diagnosticable {  T get widget => _widget!;  T? _widget;
复制代码


这里的_widget 是不需要我们自行去设置的,这个_widget 是由 flutter 框架在调用 initState 之前设置的。该_widget 实际上就是和 State 关联的 StatefulWidget。


我们可以直接在在 State 中使用 widget 来引用它。

State 的生命周期

讲完 StatefulWidget 和 State 的关系之后,接下来我们来了解一下 State 是如何变化的,通俗的讲,就是 State 的生命周期是怎么样的。


通常来说,一个 State 的生命周期有 4 个状态,分别是 created,initialized,ready 和 defunct 状态,这四个状态是定义在枚举类_StateLifecycle 中的:


enum _StateLifecycle {  /// State已经被创建成功了,State.initState方法被调用。  created,
/// State.initState方法虽然被调用了,但是State对象还没有构建完毕。 这时候会调用State.didChangeDependencies方法. initialized,
/// State对象创建成功,State.dispose方法还没有被调用。 /// called. ready,
/// State.dispose方法被调用过了,State对象不允许再调用build方法。 defunct,}
复制代码


我们详细来讲解一下 State 的生命周期。


首先,flutter 为了创建 State 对象,会调用 StatefulWidget.createState 方法。因为 StatefulWidget.createState 方法只是简单的 new 一个 State 对象,所以这个时候 State 对象就处于 created 的状态。


这个新创建的 State 对象会和一个 BuildContext 相关联.注意这个关联关系是永久性的,不会发生变化的。


虽然关联关系不会发生变化,但是 BuildContext 本身是可以在树上进行移动的。这时候的 State 处于 mounted 状态。


接下来,flutter 会调用 State 中的 initState 方法。


对于 State 的具体实现来说,需要重写这个 initState 的方法,根据和 State 关联的 BuildContext 和 Widget 来初始化 State 的状态。其中 BuildContext 和 Widget 可以通过使用 State 的 context 和 widget 属性来访问获取。


然后 flutter 框架会调用 state 的 didChangeDependencies 方法。


什么时候会去调用这个方法呢?根据 flutter 的说法,当 State 依赖的对象发生变化的时候就会调用。


举个例子,如果在 State 的 build 方法中引用了一个 InheritedWidget 对象,而这个 InheritedWidget 对象后来发生了变化。这个时候 flutter 就会调用 didChangeDependencies 方法。


我们看下 State 中该方法的定义:


  void didChangeDependencies() { }
复制代码


可以看到这个方法本身是一个空的方法体,因为并不是抽象方法,所以子类并不需要强制实现它。


为什么一般来说 State 的子对象并不需要重写这个方法呢?这是因为 flutter 如果检测到依赖有变化的时候,会去调用 State 的 build 方法。通常来说,我们并不需要这么频繁的进行重构。


当然,也会有一些特殊的情况,比如实时网络通讯这种实时性要求很高的情况。


这个时候,State 对象完全初始化完毕了,接着就可以无限次数调用 build 方法,来重构用户界面。


State 还可以主动调用 setState 方法来重构子树。


除了 State 主动调用 setState 方法之外,还有一些外部的变动会导致 State 的变动,比如:


void didUpdateWidget(covariant T oldWidget) { }
复制代码


这个方法什么时候会被调用呢?


我们知道 Widget 是不会变的,每个 Widget 都有一个唯一的 key 用来标记,但是 parent Widget 可以使用同一个 key 和 runtimeType 来对当前的 widget 进行修改。因为 Widget 是不变的,所以生成一个新的 widget。这时候 flutter 就会调用 State 中的 didUpdateWidget 方法,并且将老的 Widget 作为参数传入。


注意,flutter 框架会在调用 didUpdateWidget 之后自动调用 build 方法,所以我们在写程序的过程中,注意不要重复调用。


如果是在开发过程中,flutter 还支持热重载,这时候会调用 state 的 reassemble 方法:


void reassemble() { }
复制代码


flutter 框架会在触发热重载之后,调用 build 方法,所以一般来说,我们并不需要重写 reassemble 方法。


刚刚我们提到了 parent Widget 可能修改当前 Widget 的配置文件,如果修改了当前 Widget 的 key,那么老的 widget 就处于一个 deactivate 的状态,widget 中的 deactivate 方法就会被调用:


  void deactivate() {    super.deactivate();    assert(      !renderObject.attached,      'A RenderObject was still attached when attempting to deactivate its '      'RenderObjectElement: $renderObject',    );  }
复制代码


我们可以重写这个方法,来处理一些资源的清理工作。


注意,现在这个 widget 是 deactivate 状态,但是并不意味这它就没有用了。因为 flutter 还可以将这个 widget 再重新插入对象树中,继续使用。reinsert 是通过调用 State 对象的 build 方法来实现的。


这个操作只要是在一个 animation frame 结束之前操作都是可以的。这样做的好处就是,state 还可以保留部分资源并不释放,从而提升效率。


最后,如果 State 确实是不需要使用了,就会调用 State 的 dispose 方法:


  void dispose() {    assert(_debugLifecycleState == _StateLifecycle.ready);    assert(() {      _debugLifecycleState = _StateLifecycle.defunct;      return true;    }());  }
复制代码


当 State 的 dispose 方法被调用之后,State 就处于 unmounted 状态。这时候 State 的 setState 方法就不能再被调用了,这就表示 State 的生命周期结束了。

总结

以上就是 State 和 State 的生命周期相关的介绍。


更多内容请参考 http://www.flydean.com/03-flutter-state/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 刚刚阅读数: 4
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:用来管理复杂状态的State详解_flutter_程序那些事_InfoQ写作社区