flutter 状态管理模式之-学习providers基本用法

一、什么是provider

Provider是谷哥用来替换之前的状态管理 Provide,虽然只有一个字母之差使用方式差别却很大。Flutter 针对不同类型对象提供了多种不同的 Provider;Provider 也是借助了 InheritWidget,将共享状态放到顶层 MaterialApp 之上。

Provider 能提供你:

  • 简化资源分配/处置
  • 延迟加载
  • 每次都制作新类时大大减少了样板
  • devtools友好
  • 使用这些InheritedWidget的常用方法(请参阅Provider.of / Consumer / Selector)
  • 侦听机制的复杂度呈指数增长,从而提高了类的可伸缩性(例如ChangeNotifier,它是用于调度通知的复杂度O(N²))

二、Provider组件的使用

因为项目里使用的是 provider: ^4.0.4,所以以这个版本的为主。
现在到了 5.0.0 ,大概看了一下更新优化了不少,有兴趣的可以去看看。

Consumer的基本用法
新建一个数据提供类,这个类主要是用来提供数据

class DataProvider extends ChangeNotifier{
    
    
  int count=0;
  int count1=0;


  void add(){
    
    
    count++;
    print("count:$count");
    notifyListeners();
  }
  void add1(){
    
    
    count1++;
    print("count1:$count1");
    notifyListeners();
  }

}

```bash
    return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Column(
        children: <Widget>[
          Consumer<DataProvider>(builder: (_, data, __) {
    
    
            print("text1 rebuild");
            return Text(data.count.toString());
          }),
          Consumer<DataProvider>(builder: (_, data, __) {
    
    
            print("text2 rebuild");
            return Text(data.count1.toString());
          }),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count"),
              ),
            ),
          ),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count1"),
              ),
            ),
          ),
        ],
      ),
    );

运行结果:

I/flutter (24104): count:1
I/flutter (24104): text1 rebuild
I/flutter (24104): text2 rebuild

Consumer的其他写法

class ChildAWidget extends StatelessWidget {
    
    
  final Widget child;
  final dynamic data;

  ChildAWidget({
    
    this.child, this.data});

  @override
  Widget build(BuildContext context) {
    
    
    print("ChildAWidget build");
    return Container(
      child: Column(
        children: <Widget>[Text("$data" ?? "ChildAWidget"), child],
      ),
    );
  }
}

class ChildBWidget extends StatelessWidget {
    
    
  @override
  Widget build(BuildContext context) {
    
    
    print("ChildBWidget build");
    return GestureDetector(
      onTap: () {
    
    
        Provider.of<DataProvider>(context).add();
      },
      child: Container(
        child: Text("点我啊"),
      ),
    );
  }
}

 return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Consumer<DataProvider>(
        builder: (_, data, child) => ChildAWidget(
          child: child,
          data: data.count,
        ),
        child: ChildBWidget(),
      ),
    );

这个例子中, ChildBWidget是在 builder 之外进行重绘的。然后 ChildAWidget实例作为最一个参数传递给给 builder 。
这意味着 builder 会被反复调用时, Consumer 并不会创建 ChildBWidget新实例。这会让 Flutter 知道不必重新绘制 ChildBWidget。所以通过这么样的一个写法,当 DataProvider有更新时,只有 ChildAWidget才会进行重绘。

selector基本用法

    return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Column(
        children: <Widget>[
          Selector<DataProvider, int>(selector: (_, store) => store.count, builder: (_, data, __){
    
    
            {
    
    
              print("text1 rebuild");
              return Text(data.toString());
            }
          }),
          Selector<DataProvider, int>(selector: (_, store) => store.count1, builder: (_, data, __){
    
    
            {
    
    
              print("text2 rebuild");
              return Text(data.toString());
            }
          }),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count"),
              ),
            ),
          ),
          Consumer<DataProvider>(
            builder: (_, data, __) => GestureDetector(
              onTap: () {
    
    
                data.add1();
              },
              child: Container(
                margin: EdgeInsets.all(30),
                decoration: BoxDecoration(border: Border.all(color: Colors.red)),
                child: Text("我增加了count1"),
              ),
            ),
          ),
        ],
      ),
    );

运行结果:

I/flutter (24104): count:1
I/flutter (24104): text1 rebuild

selector其他写法

 return ChangeNotifierProvider(
      create: (_) => DataProvider(),
      child: Selector<DataProvider, int>(
        builder: (_, d, child) => ChildAWidget(
          child: child,
          data: d,
        ),
        shouldRebuild: (pre,next)=>pre!=next,
        selector: (BuildContext c, DataProvider d) {
    
    
          return d.count;
        },
        child: ChildBWidget(),
      ),
    );

如果想使用多个provider的话,可以使用MultiProvider。

    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: DataProvider()),
        ChangeNotifierProvider.value(value: DataProvider1()),
      ],
      child: ChildCWidget(),
    );

三、总结

其实consumer和selector用法上没多大区别,有点区别的是,consumer只要是值改变了都会通知它的宿主刷新UI,而selector能够选取部分值更新。Selector控制的粒度比Consumer更细,Consumer是监听一个Provider中所有数据的变化,Selector则是监听某一个/多个值的变化。从上面的运行结果就可以看出来。

还有一些provider的组件没介绍,我基本是自己在项目上用到才会写。好了,完结撒花,又记录了一个学习的过程。

猜你喜欢

转载自blog.csdn.net/hjjdehao/article/details/114948377