FlutterFlutter中文社区Flutter圈子

StatefulWidget 基础知识

2021-10-22  本文已影响0人  DaZenD

本篇主要认识StatefulWidget、了解其状态管理,简单使用,生命周期等

1. 初始StatefulWidget

@immutable

看源码,StatefulWidget也是继承自Widget,其上有个注解:@immutable,该注解的意思就是不可变的意思,作用就是widget及其子类是不可变的,定义的变量必须是final的,所以,这就无法在StatelessWidget内实现数据更新操作。

官方@immutable解释

1.1. StatefulWidget 状态管理

StatefulWidget是相对于StatelessWidget实现可变的widget,StatefulWidget也是继承于widget,所以,自然在widget内是做不了变量更新的

既然Widget是不可变,那么StatefulWidget如何来存储可变的状态呢?

Flutter将StatefulWidget设计成了两个类:

基本结构如下:

class MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // 将创建的State返回
    return MyState();
  }
}

class MyState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return <构建自己的Widget>;
  }
}

2. StatefulWidget简单使用

实现效果:

StatefulWidget_demo1.png

代码:

class HomeBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("HomeBody build");
    return MyCounterWidget();
  }
}

class MyCounterWidget extends StatefulWidget {

  MyCounterWidget() {
    print("执行了MyCounterWidget的构造方法");
  }

  @override
  State<StatefulWidget> createState() {
    print("执行了MyCounterWidget的createState方法");
    // 将创建的State返回
    return MyCounterState();
  }
}

class MyCounterState extends State<MyCounterWidget> {
  int counter = 0;

  MyCounterState() {
    print("执行MyCounterState的构造方法");
  }

  @override
  void initState() {
    super.initState();
    print("执行MyCounterState的init方法");
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print("执行MyCounterState的didChangeDependencies方法");
  }

  @override
  Widget build(BuildContext context) {
    print("执行执行MyCounterState的build方法");
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              RaisedButton(
                color: Colors.redAccent,
                child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter++;
                  });
                },
              ),
              RaisedButton(
                color: Colors.orangeAccent,
                child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),),
                onPressed: () {
                  setState(() {
                    counter--;
                  });
                },
              )
            ],
          ),
          Text("当前计数:$counter", style: TextStyle(fontSize: 30),)
        ],
      ),
    );
  }

  @override
  void didUpdateWidget(MyCounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("执行MyCounterState的didUpdateWidget方法");
  }

  @override
  void dispose() {
    super.dispose();
    print("执行MyCounterState的dispose方法");
  }
}

分析

3. 生命周期

不多解释,既然是个对象,就有生命流程,生命周期也是ui开发数据管理的基本着力点。

过程

首先,执行StatefulWidget中相关的方法:

其次,调用createState创建State对象时,执行State类的相关方法:

上面的代码直接运行,打印如下:

flutter: HomeBottomBar 构造函数
flutter: HomeBody build
flutter: 执行了MyCounterWidget的构造方法
flutter: 执行了MyCounterWidget的createState方法
flutter: 执行MyCounterState的构造方法
flutter: 执行MyCounterState的init方法
flutter: 执行MyCounterState的didChangeDependencies方法
flutter: 执行执行MyCounterState的build方法
flutter: HomeBottomBar 构造函数

// 注意:Flutter会build所有的组件两次,如果你是用as开发的话,会有这个问题,但是vscode是正常的,或者flutter run 方法启动,也是只调用一遍的,所以,不用太在意,可以理解为是as的bug,运行到手机上肯定是正常的
flutter: HomeBody build
flutter: 执行了MyCounterWidget的构造方法
flutter: 执行MyCounterState的didUpdateWidget方法
flutter: 执行执行MyCounterState的build方法

//当我们改变状态,手动执行setState方法后会打印如下结果:
flutter: 执行执行MyCounterState的build方法

3.1. 深入分析

mounted

/// Whether this [State] object is currently in a tree.
  ///
  /// After creating a [State] object and before calling [initState], the
  /// framework "mounts" the [State] object by associating it with a
  /// [BuildContext]. The [State] object remains mounted until the framework
  /// calls [dispose], after which time the framework will never ask the [State]
  /// object to [build] again.
  ///
  /// It is an error to call [setState] unless [mounted] is true.
  bool get mounted => _element != null;

1、第一句:用于判断state是否在widget树中,也就是判断widget是否加载

2、最后一句:widget加载之前,是不能调用setState的。

3、其他,表示state挂载原理和生命周期

所以,开发中,一般开发中,更新状态的时候,会有widget是否加载的判断,以免报错:

if(mounted){
    setState((){   
       
    }) 
}

dirty state & clean state

dirty state

clean state的含义是干净的State

所以,流程就是,当setState调用的时候,_element!.markNeedsBuild();将widget标记为需要build将dirty=true,然后调用scheduleBuildFor将widget加入dirty的widget列表等待rebuild,然后触发更新去rebuild,完后,将widget的dirty=false,这时候state就是clean干净的了

上一篇下一篇

猜你喜欢

热点阅读