生命周期的概念

  1. 什么是生命周期?

生命周期说白了就是回调的方法函数,让开发者知道当前的Widget处于什么样的状态

  1. 有什么作用?
  • 监听Widget的事件
  • 初始化数据:创建数据、发送网络请求
  • 内存管理:销毁数据和监听者、销毁Timer等

Widget的生命周期

  1. 无状态的Stateless
  • 构造方法
  • build方法

    1. class SearchCell extends StatelessWidget {
    2. // const SearchCell();
    3. SearchCell(){
    4. print('构造方法被调用');
    5. };
    6. @override
    7. Widget build(BuildContext context) {
    8. print('build方法被调用');
    9. return Container();
    10. }

    image.png

  1. 有状态的Stateful(包含两个对象Widget、State)
  • Widget的构造方法
  • Widget的CreatState
  • State的构造方法
  • State的initState方法
  • didChangeDependencies方法:改变依赖关系,依赖(共享数据)的InheritedWidget发生变化之后,方法也会调用
  • State的build方法,当调用setState方法,会重新调用build进行渲染
  • State的dispose方法,销毁时调用
  1. class SearchPage extends StatefulWidget {
  2. SearchPage(){
  3. print('Widget的构造方法');
  4. }
  5. @override
  6. _SearchPageState createState() {
  7. print('Widget的CreatState');
  8. return _SearchPageState();
  9. }
  10. }
  11. class _SearchPageState extends State<SearchPage> {
  12. _SearchPageState() {
  13. print('State的构造方法');
  14. }
  15. @override
  16. void initState() {
  17. // TODO: implement initState
  18. super.initState();
  19. print('State的initState方法');
  20. }
  21. @override
  22. void dispose() {
  23. // TODO: implement dispose
  24. super.dispose();
  25. print('State的dispose方法');
  26. }
  27. @override
  28. void didChangeDependencies() {
  29. // TODO: implement didChangeDependencies
  30. super.didChangeDependencies();
  31. print('didChangeDependencies方法');
  32. }
  33. @override
  34. Widget build(BuildContext context) {
  35. print('State的build方法');
  36. return Container();
  37. }
  38. }

使用Flutter Hot Restart
image.png
使用Flutter Hot Reload
image.png

  1. setState方法内部:

image.png
_element的类型:StatefulElement? _element;

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

从这里能够看出这里的_element其实就是当前的context,所以这也就是为什么调用setState方法会重新走一遍build的原因 => 等价代换如下:

  1. context as StatefulElement;
  2. context.markNeedsBuild();

上面两行代码的效果和setState是一样的!

  1. InheritedWidget数据共享

如果A的数据需要传递到B的话,我们之前是在构造方法里面传递,如下面的示例代码,这种的didChangeDependencies方法只会调用一次。

  1. class InheritedDemo extends StatefulWidget {
  2. const InheritedDemo({Key? key}) : super(key: key);
  3. @override
  4. _InheritedDemoState createState() => _InheritedDemoState();
  5. }
  6. class _InheritedDemoState extends State<InheritedDemo> {
  7. int _count = 0
  8. @override
  9. Widget build(BuildContext context) {
  10. return Column(
  11. children: [
  12. SizedBox(height: 200),
  13. TextCount(count: _count),// _count通过组件的构造方法来传递
  14. ElevatedButton(
  15. onPressed: () {
  16. _count++;
  17. setState(() {});
  18. },
  19. child: Text('点我'),
  20. )
  21. ],
  22. );
  23. }
  24. }
  25. class TextCount extends StatefulWidget {
  26. final int count;
  27. TextCount({required this.count});
  28. @override
  29. _TextCountState createState() => _TextCountState();
  30. }
  31. class _TextCountState extends State<TextCount> {
  32. @override
  33. Widget build(BuildContext context) {
  34. return Text(widget.count.toString());
  35. }
  36. }

这里我们介绍一个新的数据共享的方式InheritedWidget,看一下该组件的内部方法还是比较简单的:

  1. abstract class InheritedWidget extends ProxyWidget {
  2. // 父类的构造方法
  3. const InheritedWidget({ Key? key, required Widget child })
  4. : super(key: key, child: child);
  5. @override
  6. InheritedElement createElement() => InheritedElement(this);
  7. @protected
  8. bool updateShouldNotify(covariant InheritedWidget oldWidget);
  9. }
  • 首先定义一个共享数据类继承于该小部件
  • 其次实现构造方法,该构造方法可以参考InheritedWidget抽象基类的方法
  • 最后定义一个类方法提供给外部使用来便捷获取数据
  • 同时选择实现更新数据就去通知依赖共享数据的小部件 ```dart class MyData extends InheritedWidget { final int count; // 构造方法 const MyData({required this.count, required Widget child})
    1. : super(child: child);
    // 类方法提供给外部使用方便 拿到数据 static MyData? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); }

// 数据发生变化时 是否通知 @override bool updateShouldNotify(MyData oldWidget) { return oldWidget.count != count; } }

  1. 那怎么使用,才能把数据和组件关联上呢?
  2. - 保存和关联:在build方法里面使用构造方法,拿到数据保存和关联也就是需要使用该数据的小部件
  3. - 取出:在小部件需要使用的时候调用类方法拿出
  4. ```dart
  5. class _InheritedDemoState extends State<InheritedDemo> {
  6. int _count = 0;
  7. @override
  8. Widget build(BuildContext context) {
  9. return MyData( // 在这里使用
  10. count: _count,
  11. child: ....
  12. );
  13. }
  14. }
  15. class _TextCountState extends State<TextCount> {
  16. @override
  17. Widget build(BuildContext context) {
  18. return Text(MyData.of(context)!.count.toString());
  19. }
  20. @override
  21. void didChangeDependencies() {
  22. // TODO: implement didChangeDependencies
  23. super.didChangeDependencies();
  24. print('didChangeDependencies方法');
  25. }
  26. }

此时每次点击的时候都会再次调用didChangeDependencies方法
image.png

Widget的渲染原理

并不是所有的Widget都会被独立渲染!只有集成RenderObjectWidget的才会创建RenderObject对象!在Flutter渲染的流程中,有三个重要的树,Flutter引擎是针对Render树进行渲染!

  1. Widget树、Element树、Render树
  • 每一个Widget都会创建一个Element对象
  • 隐式调用creatElement方法,Element加入Element树
    • RenderElement
    • StatefulElement
    • StatelessElement
  1. RenderElement
  • RenderElement主要是创建RenderObject对象(继承RenderObjectWidget的Widget会创建RenderElement
    • Fluter会调用mount方法,创建RanderObject对象
  1. StatefulElement
  • StatefulElement继承ComponentElement(StatefulWidget会创建StatefulElement)
    • 调用creatState方法,创建State
    • 将Widget赋值给state state._widget = widget;
    • 调用state的build方法并且将Element也就是自己本身传递出去

image.png

  1. StatelessElement
  • StatelessElement继承ComponentElement(StatelessWidget会创建StatelessElement)
    • Stateless会创建Element
    • 然后Element创建就会调用mount方法
    • mount里面会调用widget的bulid方法进行渲染,并且将Element自己本身传递出去

image.png