Flutter移动应用:状态管理

原文链接https://siques.cn/p/41
这个章节我们会先介绍一下 Flutter 的 StatelessWidget ,还有 StatefulWidget

然后会用一个非常简单的例子来理解一下 Flutter 应用的状态管理 .. 状态就是小部件里的数据 .. 小部件可以自己管理需要的数据 .. 这些数据也可以通过小部件的构造函数从它的父辈那里传递过来 ..

我们还会学一下,使用 InheritedWidget ... 还有 ScopedModel,更有效的去把数据传递给需要的小部件 ...

小部件

StatelessWidget:无变化状态的小部件

StatelessWidget,这种小部件里面不包含可以变化的状态,State 指的就是状态,状态可以想成是小部件里的数据 .. 也就是 StatelessWidget 小部件一但被创建以后 .. 它里面的状态一般不会有什么变化 ..
Flutter移动应用:状态管理_第1张图片
下面再把 count 的值输出到控制台上检查一下 .. 打开调试控制台 ..

按一下界面上的这个漂浮按钮 .. 你会发现,每次按这个按钮的时候,count 的值都会加上 1 ... 不过在界面上这个 Chip 里面显示的 count 的值没有发生改变 ..

我们创建的小部件的状态会根据用户行为发生变化 ... 这个时候我们需要考虑使用另一种小部件,StatefulWidget ..

StatefulWidget:带变化状态的小部件

StatefulWidget,这种类型的小部件里面可以有一些能够变化的状态 .. 也就是 StaefulWidget 构建的用户界面可以动态的发生变化 .. 比如在我们这个例子里面 .. 点了这个漂浮按钮,界面上显示的这个数字要动态的发生变化 .. 这种情况我们就可以使用一个 StaefulWidget ..

下面可以把我们这个小部件改造成一个 StatefulWidget .. 让它继承一下 StatefulWidget .. 要注意的是 StaefulWidget 小部件本身也是 immutable ,不可改变的 ..

小部件需要的可以变化的那些状态要单独放在一个 State 对象里面 .. 这个 State 对象可以使用小部件里的 createState 这个方法来创建 .
Flutter移动应用:状态管理_第2张图片

然后到模拟器上再试一下 .. 按一下这个动作按钮 .. count 的值会加上 1,这个变化是在 setState 方法里面完成的,所以每次有变化,小部件都会使用新的状态被重建 .. 重建以后,界面上会显示小部件变化之后的状态 ..

状态管理(由父辈管理状态)

在我们这个 StateManagementDemo 小部件里面 .. 小部件的状态是它自己管理的 .. 它需要的所有的状态都在这个小部件自己这里 .. 有时候这个状态可能在小部件的父辈那里 .. 把 State 从父辈那里传递过来,可以通过小部件的构造函数 ..

Flutter移动应用:状态管理_第3张图片
使用这个 Counter 的时候,现在需要提供一个 count 属性 .. 这个属性的值可以使用上面定义的这个 _count ...

现在 Counter 小部件里面需要的数据是从它爸爸,也就是 StateManagementDemo 那里传递过来的 ...

从父辈那里传递个回调

下面我们再改造一下这个 Counter 小部件 .. 把这个 Chip 换成一个 ActionChip ,这样可以给它一个 onPressed 属性,设置一下点按这个 Chip 要执行的动作 .. 我想在按它的时候也可以让 _count 的值加上 1 ..

如果在这个 Counter 小部件里面设置它的这个 count ,界面上显示的数字是不会有什么变化的 .. 因为这个数字其实是 StateManagementDemo 里面的 _count 的的值 ..
Flutter移动应用:状态管理_第4张图片

按一下界面上的这个 ActionChip ... 执行的就是它爸爸传递过来的一个回调 .. 做的事儿就是让小部件的 _count 的值加上 1 ..

再按一下漂浮动作按钮 .... 同样可以增加 _count 的值 ...

状态树

Flutter移动应用:状态管理_第5张图片
现在,在 Counter 里面需要的数据是通过小部件的构造函数,从 StateManagementDemo 那里直接传递过来的 .. 假设在这两个小部件之间还有一个小部件 .. 比如可能有一个 CounterWrapper .. 在这个 CounterWrapper 里面使用了 Counter ...

这样,这个 Counter 需要的数据要先从 StateManagementDemo 传递给 CounterWrapper .. 然后再由这个 CounterWrapper 传递给 Counter .. 需要一级一级往下传 ..
Flutter移动应用:状态管理_第6张图片

InheritedWidget

InheritedWidget:直接把数据传递给需要的小部件

在我们这个示例里面,Counter 小部件需要的数据是从 StateManagementDemo 传递给 CounterWrapper,又从 CounterWrapper 传递给了 Counter ... 现在我们需要一种方法,可以把数据直接传递给需要的小部件 .. 也就是 Counter 需要的数据可以不通过 CounterWrapper,而是直接从 StateManagementDemo 那里传递过来 ..

可以试一下 Flutter 的 InheritedWidget .. 用法就是可以去创建一个 InheritedWidget,在这个小部件里面设置其它小部件需要的数据,然后把这个 InheritedWidget 放在小部件树的某个地方,这样在树下面的小部件都可以直接访问到在 InheritedWidget 小部件里的数据了 ..
Flutter移动应用:状态管理_第7张图片

ScopedModel

ScopedModel:安装与基本用法介绍

ScopedModel 也可以把数据直接交给需要的小部件 .. 它是一个第三方的包,所以要使用它得先去安装一下 .. 打开项目下面的 pubspec.yaml ..
Flutter移动应用:状态管理_第8张图片
使用 ScopedModel .. 我们得先去创建一个 Model .. 在里面添加需要的数据 .. 然后把 ScopedModel 小部件放到 Widget Tree 的某个位置上 .. 设置一下它的 model .. 这样在它下面的小部件都可以直接访问到它设置的 model 里的东西 ..

使用 ScopedModel 传递数据

先创建一个 Model .. 添加一个类 .. 名字可以是 CounterModel .. 它要继承一下 Model ... 再导入需要的包 .. 就是之前我们安装的这个 scoped_model ..

里添加一个 int _count .. 让它先等于 0 .. 再添加一个 getter 方法, 名字叫 count .. 让它返回 _count 的值 ... 在使用了这个 model 的小部件里面,可以使用这个 getter 方法获取到 _count 的值 ..

Flutter移动应用:状态管理_第9张图片
按一下界面上的 ActionChip ,会让 CounterModel 的 _count 的值增加 1 ,有变化就会重建这个部件显示出变化之后的样子 ..

同样,按一下漂浮动作按钮,也可以让 CounterModel 里的 _count 的值加上 1 ...
最终代码

import 'package:flutter/material.dart';
import "package:scoped_model/scoped_model.dart";

class StateManagementDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModel(
        model: CounterModel(),
        child: Scaffold(
            appBar: AppBar(
              title: Text('StateManagementDemo'),
              elevation: 0.0,
            ),
            body: CouterWrapper(),
            floatingActionButton: ScopedModelDescendant(
              rebuildOnChange: false,
              builder: (context, _, model) => FloatingActionButton(
                child: Icon(Icons.add),
                onPressed: model.increaseCount,
              ),
            )));
  }
}

class CouterWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Counter(),
    );
  }
}

class Counter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModelDescendant(
        builder: (context, _, model) => ActionChip(
              label: Text('${model.count}'),
              onPressed: model.increaseCount,
            ));
  }
}

class CounterProvider extends InheritedWidget {
  final int count;
  final VoidCallback increaseCount;
  final Widget child;

  // 构造函数
  CounterProvider({this.count, this.increaseCount, this.child})
      : super(child: child);

  static CounterProvider of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType();

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

class CounterModel extends Model {
  int _count = 0;
  int get count => _count;

  void increaseCount() {
    _count += 1;
    notifyListeners();
  }
}

你可能感兴趣的:(flutter,dart)