likes
comments
collection
share

Flutter进阶-生命周期

作者站长头像
站长
· 阅读数 27

生命周期的概念

  1. 什么是生命周期?

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

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

Widget的生命周期

  1. 无状态的Stateless
    • 构造方法
    • build方法
class SearchCell extends StatelessWidget {
 // const SearchCell();
  SearchCell(){
    print('构造方法被调用');
  };
  
  @override
  Widget build(BuildContext context) {
    print('build方法被调用');
    return Container();
}

Flutter进阶-生命周期

  1. 有状态的Stateful(包含两个对象WidgetState
    • Widget的构造方法
    • Widget的creatState
    • State的构造方法
    • State的initState方法
    • didChangeDependencies方法:改变依赖关系,依赖(共享数据)的InheritedWidget发生变化之后,方法也会调用
    • State的build方法,当调用setState方法,会重新调用build进行渲染
    • State的dispose方法,销毁时调用
class SearchPage extends StatefulWidget {
  SearchPage(){
    print('Widget的构造方法');
  }

  @override
  _SearchPageState createState() {
    print('Widget的CreatState');
    return _SearchPageState();
  }
}

class _SearchPageState extends State<SearchPage> {
  _SearchPageState() {
    print('State的构造方法');
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print('State的initState方法');
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print('State的dispose方法');
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies方法');
  }
  
   @override
  Widget build(BuildContext context) {
    print('State的build方法');
    return Container();
  }
}

使用Flutter Hot Restart

Flutter进阶-生命周期

使用Flutter Hot Reload

Flutter进阶-生命周期

  1. setState方法内部:

Flutter进阶-生命周期 _element的类型:StatefulElement? _element;

  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其实就是当前的context,所以这也就是为什么调用setState方法会重新走一遍build的原因 => 等价代换如下:

context as StatefulElement;
context.markNeedsBuild();

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

  1. InheritedWidget数据共享

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

class InheritedDemo extends StatefulWidget {
  const InheritedDemo({Key? key}) : super(key: key);

  @override
  _InheritedDemoState createState() => _InheritedDemoState();
}

class _InheritedDemoState extends State<InheritedDemo> {
  int _count = 0
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(height: 200),
        TextCount(count: _count),// _count通过组件的构造方法来传递
        ElevatedButton(
          onPressed: () {
            _count++;
            setState(() {});
          },
          child: Text('点我'),
        )
      ],
    );
  }
}

class TextCount extends StatefulWidget {
  final int count;
  TextCount({required this.count});

  @override
  _TextCountState createState() => _TextCountState();
}

class _TextCountState extends State<TextCount> {
  @override
  Widget build(BuildContext context) {
    return Text(widget.count.toString());
  }
}

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

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

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

那怎么使用,才能把数据和组件关联上呢?

    • 保存和关联:在build方法里面使用构造方法,拿到数据保存和关联也就是需要使用该数据的小部件
    • 取出:在小部件需要使用的时候调用类方法拿出
class _InheritedDemoState extends State<InheritedDemo> {
  int _count = 0;
  @override
  Widget build(BuildContext context) {
    return MyData( // 在这里使用
        count: _count,
        child: ....
    );
  }
}

class _TextCountState extends State<TextCount> {
  @override
  Widget build(BuildContext context) {
    return Text(MyData.of(context)!.count.toString());
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies方法');
  }
}

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

Flutter进阶-生命周期

Widget的渲染原理

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

  1. Widget树、Element树、Render树:每一个Widget都会创建一个Element对象。隐式调用creatElement方法,Element加入Element

    • RenderElement
    • StatefulElement
    • StatelessElement
  2. RenderElement:主要是创建RenderObject对象(继承RenderObjectWidgetWidget会创建RenderElement

    • Fluter会调用mount方法,创建RanderObject对象
  3. StatefulElement继承ComponentElement(StatefulWidget会创建StatefulElement)

    • 调用creatState方法,创建State
    • 将Widget赋值给state state._widget = widget;
    • 调用state的build方法并且将Element也就是自己本身传递出去

Flutter进阶-生命周期

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

Flutter进阶-生命周期

转载自:https://juejin.cn/post/7047480365518159902
评论
请登录