美文网首页
Flutter:StatefulWidget 的状态管理与生命周

Flutter:StatefulWidget 的状态管理与生命周

作者: 时光啊混蛋_97boy | 来源:发表于2023-01-30 15:37 被阅读0次

    原创:有趣知识点摸索型文章
    创作不易,请珍惜,之后会持续更新,不断完善
    个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
    温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

    目录

    • 一、StatefulWidget 的状态管理
    • 二、Flutter 默认 Demo 对 StatefulWidget 的使用
    • 三、StatefulWidget 的生命周期

    一、StatefulWidget 的状态管理

    StatefulWidgetStatelessWidget 均继承自 Widget

    abstract class StatefulWidget extends Widget
    abstract class StatelessWidget extends Widget
    

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

    @immutable
    abstract class Widget extends DiagnosticableTree
    

    StatefulWidget 是相对于 StatelessWidget 实现可变的 widget。由于 StatefulWidget 也是继承于 widget,所以自然在 widget 内是做不了变量更新的。既然 Widget 是不可变,那么 StatefulWidget 如何来存储可变的状态呢?

    StatelessWidget 无所谓,因为它里面的数据通常是直接定义完后就不修改的。但 StatefulWidget 需要有状态(可以理解成变量)的改变,这如何做到呢?

    FlutterStatefulWidget 设计成了两个类,也就是你创建 StatefulWidget 时必须创建两个类:一个类继承自 StatefulWidget,作为 Widget 树的一部分;另外一个类继承自 State,用于记录 StatefulWidget 会变化的状态,并且根据状态的变化,构建出新的 Widget

    基本结构如下:

    class MyStatefulWidget extends StatefulWidget {
      @override
      State< MyStatefulWidget > createState() {
        // 将创建的State返回
        return MyState();
      }
    }
    
    class MyState extends State<MyStatefulWidget> {
      @override
      Widget build(BuildContext context) {
        return <构建自己的Widget>;
      }
    }
    

    二、Flutter 默认 Demo 对 StatefulWidget 的使用

    我们来看看系统为我们默认生成的页面中对 StatefulWidget 的使用。

    这里有一个属性 title 表示的是页面的标题,其值由创建 MyHomePage 处赋予,在 Statebuild 方法中进行使用。像这样的属性,我们总是将其标记为 finalconst MyHomePage({ })表示其初始方法,需要传入父类的属性和当前类中自定义的属性。

    class MyHomePage extends StatefulWidget {
      final String title;
      const MyHomePage({super.key, required this.title});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    

    而其对应的继承自 State,用于记录 StatefulWidget 变化状态的类如下:

    class _MyHomePageState extends State<MyHomePage> {
    
    }
    

    在其中我们新增加了一个变量 _counter,其初值为0,每当点击 + 按钮调用一次 _incrementCounter 方法就会让其值增加1。由于其值的改变是在 setState 中进行的,而当在 setState 中的值发生改变的时候,就会告诉 Flutter 框架当前状态发生了改变,这将导致它重新运行下面的构建方法 build。如果我们改变 _counter 却不调用 setState(),那么构建方法 build 将不会被再次调用,看起来什么都不会发生。

    int _counter = 0;
    
    void _incrementCounter() {
      setState(() {
        _counter++;
      });
    }
    

    每次调用 setState 时都会重新运行下面这个方法。此处我们从 MyHomePage 对象中获取值,并使用它来设置我们的应用栏标题。

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: 'Increment',
          child: const Icon(Icons.add),
        ),
      );
    }
    

    MyHomePage 对象是在 MyAppbuild 方法中进行创建的。MyApp这个组件是我们应用程序的根组件。

    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    

    在入口方法 main 方法中,系统调用了 runApp 方法,将 MyApp对象作为参数进入了传入。

    void main() {
      runApp(const MyApp());
    }
    

    总结 Flutter 自定义 StatefulWidget 的套路:

    • 快捷代码模块:输入stlessstful 系统就会自动补全代码
    • 自定义 Widget:继承自 StatefulWidget,重载 createState 方法来加载自定义的 state
    • 自定义 State:继承自 State,实现你真正的 UI 部分和状态(Data)管理。自定义的 State 做状态管理,而 setState 做状态更新(更新完会触发 Widget 重新进行 build)。

    三、StatefulWidget 的生命周期

    既然是个对象,就有生命流程。StatelessWidget 可以由父 Widget 直接传入值,调用 build 方法来构建,整个过程非常简单;而 StatefulWidget 需要通过 State 来管理其数据,并且还要监控状态的改变决定是否重新 build 整个 Widget,所以,我们主要讨论 StatefulWidget 的生命周期,也就是它从创建到销毁的整个过程。

    1、StatefulWidget 类

    class MyCounterWidget extends StatefulWidget {
    
    }
    

    执行 StatefulWidget 的构造函数(Constructor)来创建出 StatefulWidget

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

    执行 StatefulWidgetcreateState 方法,来创建一个维护 StatefulWidgetState 对象

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

    2、State 类

    class MyCounterState extends State<MyCounterWidget> {
    
    }
    

    执行 State 类的构造方法(Constructor)来创建 State 对象。

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

    执行 initState。我们通常会在这个方法中执行一些数据初始化的操作,或者也可能会发送网络请求。

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

    注意这个方法是重写父类的方法,必须调用 super,因为父类中会进行一些其他操作。并且如果你阅读源码,你会发现这里有一个注解(annotation):@mustCallSuper

    @protected
    @mustCallSuper
    void initState() {
      assert(_debugLifecycleState == _StateLifecycle.created);
    }
    

    执行 didChangeDependencies 方法,这个方法在两种情况下会调用。

    • 情况一:调用 initState 方法时会被调用
    • 情况二:从其他对象中依赖一些数据发生改变时,比如 InheritedWidget
    @override
    void didChangeDependencies() {
      super.didChangeDependencies();
      print("MyCounterState:执行 didChangeDependencies 方法");
    }
    

    Flutter 执行 build 方法,来看一下我们当前的 Widget 需要渲染哪些 Widget

    @override
    Widget build(BuildContext context) {
        print("MyCounterState:执行 build 方法");
        return Center( )
    }
    

    当前的 Widget 不再使用时,会调用 dispose 进行销毁。

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

    手动调用 setState 方法,会根据最新的状态(数据)来重新调用 build 方法,构建对应的 Widgets

    setState(() {
      _counter++;
    });
    

    执行 didUpdateWidget 方法是在当父 Widget 触发重建(rebuild)时,系统会调用 didUpdateWidget 方法。

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

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

    flutter: MyApp:build
    flutter: MyCounterWidget:执行了构造方法
    flutter: MyCounterWidget:执行了 createState 方法
    
    flutter: MyCounterState:执行构造方法
    flutter: MyCounterState:执行 init 方法
    flutter: MyCounterState:执行 didChangeDependencies 方法
    flutter: MyCounterState:执行 build 方法
    

    注意这里 Flutterbuild 所有的组件两次。如果你是用 Android Studio 开发的话,会有这个问题,但是如果使用 VSCode 进行开发则是正常的,即只会调用一遍的,所以不用太在意,可以理解为是 Android StudioBug,其运行到手机上肯定是正常的。

    flutter: MyApp:build
    flutter: MyCounterWidget:执行了构造方法
    flutter: MyCounterState:执行 didUpdateWidget 方法
    flutter: MyCounterState:执行 build 方法
    

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

    flutter: MyCounterState:执行 build 方法
    

    相关文章

      网友评论

          本文标题:Flutter:StatefulWidget 的状态管理与生命周

          本文链接:https://www.haomeiwen.com/subject/xtumhdtx.html