美文网首页
Flutter 源码阅读 - StatefulWidget 源码

Flutter 源码阅读 - StatefulWidget 源码

作者: _Jun | 来源:发表于2022-12-25 15:10 被阅读0次

    Flutter 源码阅读 - 三棵树流程分析(三) 这篇文章中,笔者粗略的介绍了 StatefulWidget 的大致执行流程,并没有进行深入的分析,这篇文章将深入分析一下它的源码以及 State 的生命周期。

    一、StatefulWidget

    StatefulWidget 也是继承自 Widget,重写了 createElement,并且添加了一个新的接口 createState,下面我们看一下它的源码:

    看起来是不是很简单,代码不足十行。

    • createElement 方法返回一个 StatefulElement 类型的 Element
    • createState 抽象方法返回一个 State 类型的实例对象。在给定的位置为 StatefulWidget 创建可变状态(state)。框架可以在 StatefulWidget生命周期内多次调用此方法,比如:将 StatefulWidget 插入到 Widget Tree 中的多个位置时,会创建多个单独的 State 实例,如果将 StatefulWidgetWidget Tree 中删除,稍后再次将琦插入到 Widget Tree 中,框架将会再次调用 createState创建一个新的 State 实例对象。

    StatefulWidget 我们暂时就先讲到这里, 关于 StateStatefulElement 我们在下面会进行分析。


    二、StatefulElement

    上面讲到 StatefulWidgetcreateElement 会创建一个 StatefulElement 类型的 Element。下面我们就一起看下 StatefulElement 的源码。

    在执行 StatefulWidget#createElement 时会把 this 传递进去,此时执行 StatefulElement 的构造方法中我们可以看出会做以下三件事情:

    • 首先通过 _state = widget.createState() 执行 StatefulWidget 中的 createState 进行闯将 State 实例;
    • 其次通过 state._element = this 将当前对象赋值给 State 中的 _element 属性;
    • 最后通过 state._widget = widget,将 StatefulWidget 赋值给 State 中的 _widget 属性。

    通过以上分析我们相应的可以得出以下结论:

    • StatefulElement 持有 State 状态;
    • State 中又会反过来持有 StatefulElementStatefulWidget(当然,State 的源码我们还没有看到);
    • StatefulWidget 只是负责创建 StatefulElementState,但是并不持有它们。

    至此我们已经理清了 StatefulWidgetStatefulElementState 三者之间的关系,关于 State 我们会在后面讲到。现在我们已经知道 StatefulWidget 中的 createState 在何时执行,那么 StatefulElement#createElement 又是在何时执行的呢?下面我们来看一个例子:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(
        const MyApp(),
      );
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
        return const ColoredBox(
          color: Colors.red,
        );
      }
    }
    

    通过断点调试可以看出在 Element#inflateWidget 中 通过 newWidget.createElement() 来进行触发 StatefulWidget#createElement 的执行,进而执行 StatefulElement 的构造函数。

    关于更多 StatefulElement 内部方法,将在 State 源码以及相关案例中穿插进行。


    三、State

    State 是一个抽象类,它只定义了一个 build 抽象方法,由于构建 Widget 对象。它是通过StatefulElement#build 方法进行调用的。

    如下是 State 源码的部分截图:

    从源码中我们也可以对上面的结论得到验证,State 持有 StatefulElementStatefulWidget,这里的泛型 T 必须是 StatefulWidget 类型,如下图所示:

    除此之外 State 中还持有 BuildContext,通过源码我们可以看出 BuildContext 其实就是 StatefulElement

      BuildContext get context {
        return _element!;
      }
    

    那么现在我们可以思考一下 State 中的生命周期方法在何时调用以及在哪里调用呢?从上面我们得出的结论:StatefulElement 持有 State 状态,State 中又会反过来持有 StatefulElementStatefulWidgetStatefulWidget 只是负责创建 StatefulElementState,但是并不持有它们。不难猜测出,应该是在 StatefulElement 中来触发的,下面我通过一个小的案例来进行研究一下:

    void main() {
      runApp(
        const WrapWidget(),
      );
    }
    
    class WrapWidget extends StatelessWidget {
      const WrapWidget({
        Key? key,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text("StatefulWidget Demo"),
            ),
            body: MyApp(),
          ),
        );
      }
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({
        super.key,
      });
    
      @override
      // ignore: no_logic_in_create_state
      State<MyApp> createState() {
        debugPrint("createState");
        return _MyAppState();
      }
    }
    
    class _MyAppState extends State<MyApp> {
      late int _count = 0;
    
      @override
      void initState() {
        debugPrint("initState");
        super.initState();
      }
    
      @override
      void didChangeDependencies() {
        debugPrint("didChangeDependencies");
        super.didChangeDependencies();
      }
    
      @override
      void didUpdateWidget(MyApp oldWidget) {
        debugPrint("didUpdateWidget");
        super.didUpdateWidget(oldWidget);
      }
    
      @override
      void deactivate() {
        debugPrint("deactivate ");
        super.deactivate();
      }
    
      @override
      void dispose() {
        debugPrint("dispose");
        super.dispose();
      }
    
      @override
      void reassemble() {
        debugPrint("reassemble");
        super.reassemble();
      }
    
      @override
      Widget build(BuildContext context) {
        debugPrint("build");
        return Column(
          children: [
            Text('$_count'),
            OutlinedButton(
              onPressed: () {
                setState(() {
                  _count++;
                });
              },
              child: const Text('OnPress'),
            ),
          ],
        );
      }
    }
    

    程序刚运行时打印日志如下:

    然后我们点击⚡️按钮热重载,控制台输出日志如下:

    我们再次点击 OnPress 按钮时,打印日志如下:

    此时我们注释掉 WrapWidget 中的 body: MyApp() 这行代码,打印日志如下:

    此时结合源码,我们来一起看下各个生命周期函数:

    • initState: 当 Widget 第一次插入到 Widget Tree 中,会执行一次,我们一般在这里可以做一些初始化状态的操作以及订阅通知事件等,通过源码我们可以看出它是在 Statefulelement#_firstBuild 中执行的;
    • didChangeDependencies: 当 State 对象的依赖发生变化时会进行调用,例如:例如系统语言 Locale 或者应用主题等,通过源码我们可以看出它在 Statefulelement#_firstBuildStatefulelement#performRebuild 中都会执行;
    • build:在以下场景中都会调用:

      • initState 调用之后
      • didUpdateWidget 调用之后
      • setState 调用之后
      • didChangeDependencies 调用之后
      • 调用 deactivate 之后,然后又重新插入到 Widtget Tree

      通过源码可以看出它是在 Statefulelement#build 中执行的;

    • reassemble:专门为了开发调试而提供的,在 hot reload 时会被调用,在 Release 模式下永远不会被调用,通过源码可以看出它是在 Statefulelement#reassemble 中执行的;
    • didUpdateWidget:在 Widget 重新构建时,Flutter 框架会在 Element#updateChild 中通过Widget.canUpdate 判断是否需要进行更新,如果为 true 则进行更新;

    canUpdate 源码中,新旧 widget 的 keyruntimeType 同时相等时会返回 true,也就是说在在新旧 widgetkeyruntimeType 同时相等时 didUpdateWidget() 就会被调用;

    • deactivate:当 State 对象从树中被移除时将会调用,它将会在 Statefulelement#deactivate 中进行调用;
    • dispose:当 State 对象从树中被永久移除时调用;通常在此回调中释放资源,它将会在 Statefulelement#unmount 中进行调用。

    总结

    至此,结合一些小的案例和源码阅读,我们大致明白了 StatefulWidgetState 以及 StatefulElement 他们三者之间的关系以及 State 的生命周期,相信在以后的实际应用中会更加得心应手。

    作者:feelingHy
    链接:https://juejin.cn/post/7180626500951998520

    相关文章

      网友评论

          本文标题:Flutter 源码阅读 - StatefulWidget 源码

          本文链接:https://www.haomeiwen.com/subject/cwlgqdtx.html