Flutter -- 13.生命周期&InheritedWidget

1.生命周期的基本概念

  • 生命周期就是一系列的回调函数
  • 每个函数让你知道当前这个Widget处于什么状态

2.生命周期的作用

  • 监听Widget的事件
  • 初始化数据
       创建数据
       发送网络请求
  • 内存管理
       销毁数据、监听者
       销毁Timer

3.StatelessWidget

  • 构造方法
  • build方法

4.StatefulWidget(包含State)

  • Widget构造方法
  • Widget的createState
  • State的构造方法
  • State的initState方法
  • didChangeDependencies
       依赖的InheritedWidget发送变化时会调用
  • State的build方法
       当调用setState方法。会重新调用build进行渲染
  • 当Widget销毁的时候,调用State的dispose
class Home extends StatefulWidget {

  Home() {
    print('Home构造方法调用了');
  }

  @override
  // ignore: no_logic_in_create_state
  _HomeState createState() {
    print('createState调用了');
    return _HomeState();
  }

}

class _HomeState extends State {

  int _count = 0;
  
  _HomeState() {
    print('_HomeState构造方法调用了');
  }

  @override
  void initState() {
    print('initState调用了');
    super.initState();
  }
  
  @override
  void didChangeDependencies() {
    print('didChangeDependencies调用了');
    super.didChangeDependencies();
  }

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

  @override
  void dispose() {
    print('dispose调用了');
    super.dispose();
  }
  
}

5.关于didChangeDependencies&InheritedWidget数据共享

  • 依赖的InheritedWidget发送变化时会调用
  • 这里需要使用到一个新的类,InheritedWidget
class MyData extends InheritedWidget {

  final int data;

  //子类的构造方法里必须要有child,必须将child传给super进行赋值
  MyData({required this.data, required Widget child}) : super(child: child);

  //定义一个外界获取共享数据时需要调用的方法
  static MyData? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType();
  }
  
  /* 是否需要通知依赖该数据的子部件刷新
  * 如果子部件为StatelessWidget,无论返回true或false,执行构造函数和build。刷新视图
  *
  * 如果返回false,子部件为StateulWidget,不会执行didChangeDependencies,
  *   不会执行其它函数,Widget不会发生任何变化。
  * 如果返回true,子部件为StateulWidget,执行didChangeDependencies。
  *   然后执行build刷新Widget。
  * */
  @override
  bool updateShouldNotify(covariant MyData oldWidget) {
    return oldWidget.data != data;
  }

}
  • 关于数据共享的实现
class Home extends StatefulWidget {

  @override
  // ignore: no_logic_in_create_state
  _HomeState createState() {
    print('createState调用了');
    return _HomeState();
  }

}

class _HomeState extends State {

  int _count = 0;

  @override
  void didChangeDependencies() {
    print('didChangeDependencies调用了');
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return MyData(data: _count, child: MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: AppBarTitle()),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            const TopText(),
            CenterText(),
            Button(increase: () {
              _count ++;
              (context as StatefulElement).markNeedsBuild();
            },)
          ],
        ),
      ),
    ));
  }

}

class AppBarTitle extends StatelessWidget {
  AppBarTitle({Key? key}) : super(key: key) {
    print('AppBarTitle 构造');
  }

  /*
  * StatelessWidget
  * 这里的AppBarTitle为StatelessWidget,没有didChangeDependencies
  * 因此上层视图刷新后,该Widget会重新创建,然后执行build
  * */

  @override
  Widget build(BuildContext context) {
    return Text(MyData.of(context)!.data.toString());
  }
}

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

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

class _TopTextState extends State {

  _TopTextState() {
    print('_TopTextState 构造');
  }

  /*
    * StatefulWidget
    * 当_count改变后,执行_HomeState的build方法,不会执行_TopTextState构造函数。
    * 执行到didChangeDependencies然后执行build
    * */
  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print('didChangeDependencies');
  }

  @override
  Widget build(BuildContext context) {
    print('TopText build');
    return Center(
      child: Text(MyData.of(context)!.data.toString()),
    );
  }
}

class CenterText extends StatelessWidget {

  CenterText() {
    print('CenterText 构造');
  }

  @override
  Widget build(BuildContext context) {
    print('CenterText build');
    return const Center(
      child: Text('CenterText'),
    );
  }
}

class Button extends StatefulWidget {

  void Function()? increase;

  Button({this.increase});

  @override
  State
  • InheritedWidget将State作为保存数据,来实现当父部件刷新时,某一些子部件不刷新的功能
    • 例如MyData中data存放的是_HomeState(之前是_HomeState,去除私有)
    • 通过HomeState来获取count赋值

  • 注意:updateShouldNotify出现了新的关键字 convariant
  • 这里写了个小demo来解释一下convariant的用法及作用
class People {
  //和另一个人交谈
  chatWith(People p){}
}

class Teacher extends People {
  @override
  //如果不加covariant,会抛出异常。编译器强制要你使用People而不是Teacher
  chatWith(covariant Teacher t) {
    // TODO: implement chatWith
    print('这个老师正在和${t.getName()}聊天');
  }
  getName() {
    return '李老师';
  }
}

void main() {
  Teacher().chatWith(Teacher()); // 这个老师正在和李老师聊天
}
  • 总结来说,covariant字义为协变,即我和编译器协商,这个参数缩窄变化是我故意这样做的,你别抛异常了

6.通过InheritedWidget实现子部件不执行Rebuild

  • 实现当父部件rebuild并且子部件不需要rebuild时的需求
class MyData extends InheritedWidget {

  final HomeState data;

  //子类的构造方法里必须要有child,必须将child传给super进行赋值
  MyData({required this.data, required Widget child}) : super(child: child);

  //定义一个外界获取共享数据时需要调用的方法
  static MyData? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType();
  }

  @override
  bool updateShouldNotify(covariant MyData oldWidget) {
    return true;
  }

}

void main() {
  runApp(MaterialApp(
    home: Home(child: Scaffold(
      appBar: AppBar(title: AppBarTitle()),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          TopText(),
          CenterText(),
          Button()
        ],
      ),
    ),),
  ));
}

class Home extends StatefulWidget {

  final Widget child;

  //1.在Home里保存传入进来的Widget
  Home({required this.child});

  @override
  // ignore: no_logic_in_create_state
  HomeState createState() {
    print('createState调用了');
    return HomeState();
  }

}

class HomeState extends State {

  int count = 0;

  increase() {
    setState(() {
      count ++;
    });
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies调用了');
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    //2.将传入的child赋值给InheritedWidget子类(这里是MyData)
    return MyData(data: this, child:widget.child);
  }

}

class AppBarTitle extends StatelessWidget {
  AppBarTitle({Key? key}) : super(key: key) {
    print('AppBarTitle 构造');
  }
  
  @override
  Widget build(BuildContext context) {
    return Text(MyData.of(context)!.data.count.toString());
  }
}

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

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

class _TopTextState extends State {

  _TopTextState() {
    print('_TopTextState 构造');
  }

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

  @override
  Widget build(BuildContext context) {
    print('TopText build');
    return Center(
      child: Text(MyData.of(context)!.data.count.toString()),
    );
  }
}

class CenterText extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    print('CenterText build');
    return const Text('CenterText');
  }
}

class Button extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    print('_ButtonState build');
    return ElevatedButton(onPressed: () {
      MyData.of(context)!.data.increase();
    }, child: const Icon(Icons.add));
  }
}
  • 点击按钮时,通过控制台/Flutter Performance查看加载情况
  • CenterText不会rebuild

7.关于setState

  • 进入setState源码,将asset相关的代码折起来。
  • 除去assert后,发现只执行了一句代码_element!.markNeedsBuild();
  • 标记为脏元素,将_element加入_dirtyElements
void setState(VoidCallback fn) {
  assert(fn != null);
  assert(...);
  final Object? result = fn() as dynamic;
  assert(...);
  _element!.markNeedsBuild();
 }
  • 查看源码得知,build函数中的context其实就是_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;
  • 因此setState也就可以改为(context as StatefulElement).markNeedsBuild()
Widget build(BuildContext context) {
    print('State中build调用了');
    return Column(
      children: [
        Text('$_count'),
        ElevatedButton(onPressed: () {
          _count ++;
          (context as StatefulElement).markNeedsBuild();
        }, child: const Icon(Icons.add))
      ],
    );
  }

你可能感兴趣的:(Flutter -- 13.生命周期&InheritedWidget)