Flutter入门(十一)生命周期&渲染原理

前言

在做移动端开发时,不论是安卓的Activity还是iOS的UIViewController都有自己的生命周期,同理Flutter也有自己的生命周期,今天我们就通过以下几个方面来探索一下:

  • 1.生命周期的基本概念
  • 2.Widget的生命周期
  • 3.Flutter渲染原理

1.生命周期的基本概念

Flutter生命周期流程

1.1什么是生命周期

  • 1.说白了就是回调函数
  • 2.让你知道封装好的这个Widget处于什么样的状态

1.2生命周期的作用

  • 1.初始化数据
    1.1创建变量、常量
    1.2发送网络请求

  • 2.监听小部件的事件

  • 3.管理内存
    3.1销毁数据、销毁监听者
    3.2销毁Timer等等

2.Widget的生命周期

2.1StatelessWidget的生命周期

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
  • 1.构造方法
  • 2.build方法

对于StatelessWidget来说,生命周期只有构造和build过程。build是用来创建Widget的,在每次页面刷新时会调用build

2.2StatefulWidget的生命周期

class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({Key? key, required this.title}) : super(key: key) {
    print('Widget构造方法来了');
  }

  @override
  State<MyHomePage> createState() {
    print('Widget的createState方法调用了');
    return _MyHomePageState();
  }
}

class _MyHomePageState extends State<MyHomePage> {
  _MyHomePageState() {
    print('State构造方法来了');
  }

  @override
  void initState() {
    print('State的initState来了');
    super.initState();
  }

  @override
  void didChangeDependencies() {
    print('State的didChangeDependencies来了');
    super.didChangeDependencies();
  }

  int _count = 0;

  @override
  Widget build(BuildContext context) {
    print('State的build来了');
    return Container(
      child: Column(
        children: [
          ElevatedButton(
            onPressed: () {
              _count++;
              setState(() {});
            },
            child: const Icon(Icons.add),
          ),
          Text('$_count'),
        ],
      ),
    );
  }

  @override
  void dispose() {
    print('State的dispose来了');
    super.dispose();
  }
}
  • 1.Widget构造方法
  • 2.WidgetCreateState
  • 3.State构造方法
  • 4.StateinitState
  • 5.didChangeDependencies方法(改变依赖关系);依赖(共享数据)的InheritedWidget发生变化之后,didChangeDependencies才会调用
  • 6.StateBuild ,当调用setState方法。会重新调用Build进行渲染,setState方法内部主要是利用_element(本质是就是context对象) 调用 markNeedsBuild
  • 7.当Widget销毁的时候调用Statedispose

2.3setState实现

  @protected
  void setState(VoidCallback fn) {
    assert(fn != null);
    assert(() {
      if (_debugLifecycleState == _StateLifecycle.defunct) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called after dispose(): $this'),
          ErrorDescription(
            'This error happens if you call setState() on a State object for a widget that '
            'no longer appears in the widget tree (e.g., whose parent widget no longer '
            'includes the widget in its build). This error can occur when code calls '
            'setState() from a timer or an animation callback.',
          ),
          ErrorHint(
            'The preferred solution is '
            'to cancel the timer or stop listening to the animation in the dispose() '
            'callback. Another solution is to check the "mounted" property of this '
            'object before calling setState() to ensure the object is still in the '
            'tree.',
          ),
          ErrorHint(
            'This error might indicate a memory leak if setState() is being called '
            'because another object is retaining a reference to this State object '
            'after it has been removed from the tree. To avoid memory leaks, '
            'consider breaking the reference to this object during dispose().',
          ),
        ]);
      }
      if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() called in constructor: $this'),
          ErrorHint(
            'This happens when you call setState() on a State object for a widget that '
            "hasn't been inserted into the widget tree yet. It is not necessary to call "
            'setState() in the constructor, since the state is already assumed to be dirty '
            'when it is initially created.',
          ),
        ]);
      }
      return true;
    }());
    final Object? result = fn() as dynamic;
    assert(() {
      if (result is Future) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() callback argument returned a Future.'),
          ErrorDescription(
            'The setState() method on $this was called with a closure or method that '
            'returned a Future. Maybe it is marked as "async".',
          ),
          ErrorHint(
            'Instead of performing asynchronous work inside a call to setState(), first '
            'execute the work (without updating the widget state), and then synchronously '
            'update the state inside a call to setState().',
          ),
        ]);
      }
      // We ignore other types of return values so that you can do things like:
      //   setState(() => x = 3);
      return true;
    }());
    _element!.markNeedsBuild();
  }

setState方法其实核心就是最后一句_element!.markNeedsBuild();

  BuildContext get context {
    assert(() {
      if (_element == null) {
        throw FlutterError(
          'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
          'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',
        );
      }
      return true;
    }());
    return _element!;
  }
  StatefulElement? _element;

由上面的源码可以得出_element其实就是Statebulid方法中的context

3.Flutter渲染原理

实际上,Flutter的UI绘制包含了三个元素,WidgetElementRenderObject。这三个元素分别组成了三棵树:Widget 树,Element 树和 RenderObject树,在Flutter渲染的流程中Flutter引擎渲染是针对Render树中的对象进行渲染

Flutter三棵树

系统启动时,runApp方法会被调用,Flutter会从最外层的Widget去遍历创建一颗Widget树;

  • 每一个Widget创建出来都会调用createElement方法创建一个Element对象
  • Element加入到Element树中,形成Element
  • Element通过mount方法调用createRenderObject创建RenderObject对象,并形成相应的RenderObject

StatelessElement 继承 ComponentElement主要调用build方法,并且将自己(Element)传递出去

StatefulElement 继承 ComponentElement,调用creatState方法,创建state,将Widget赋值给State对象,调用statebuild方法,并且将自己(Element)传出去

⚠️注意
只有继承自RenderObjectWidgetWidget才能创建RenderObject并加入RenderObject树,被渲染

3.1三棵树的作用

  • Widget树:配置信息,用来描述UI特征,比如尺寸多大,颜色是什么,位置在哪里
  • Element树:element是widget的实际实例,它同时持有了widget和renderObject的引用,用来决定是否进行UI更新。
  • RenderObject树:UI更新的执行者,保存了元素的大小,布局等信息。它才是真正调用渲染引擎去进行更新的对象
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。