zoukankan      html  css  js  c++  java
  • (转)flutter 新状态管理方案 Provide (一)-使用


    flutter 新状态管理方案 Provide (一)-使用

    版权声明:本文为博主原创文章,基于CC4.0协议,首发于https://kikt.top ,同步发于csdn,转载必须注明出处! https://blog.csdn.net/qq_28478281/article/details/87858386

    开这篇文章是因为看到这个库被托管在google的仓库下,而且说明是被设计出来替代ScopedModel的,而且更加灵活

    支持Builder模式和StreamBuilder模式,全局,局部都可以

    内部应该是结合InheritedWidget Notification体系实现的

    传统的bloc需要在每一个Repository中创建StreamControllerStream,甚至有的文章中,一个监听的修改需要修改5处,维护起来比较麻烦

    相比较而言Provide维护起来会稍微省事一些

    入门级仓库地址

    添加依赖

    查看pub-install

    dependencies:
      provide: ^1.0.1 # 这里的版本查看官方

    flutter packages get

    import 'package:provide/provide.dart';

    使用方法

    这里以简单的Counter为例
    也就是在flutter的hello world工程的基础上来修改

    1. 定义一个Model

    这个model需要继承ChangeNotifier

    class Counter with ChangeNotifier {
      int _value;
    
      int get value => _value;
    
      Counter(this._value);
    
      void inc() {
        _value++;
        notifyListeners(); //父类的方法,发出通知
      }
    }

    2. 定义一个全局的Provide

    这里虽然定义在全局,但事实上也可以定义在页面级

    void main() {
      var providers = Providers()..provide(Provider.function((ctx) => Counter(0)));
    
      runApp(
        ProviderNode(
          child: MyApp(),
          providers: providers,
        ),
      );
    }

     

    ProviderNode表示的是提供者

    3. 界面/监听

    修改_MyHomePageState

    添加一个方法,用于获取Counter实例

    Counter get _counter => Provide.value<Counter>(context);

    将原来的Text(_counter)修改一下

    这里的Provide会在Counter发生变化的时候,触发builder回调来更新界面

    Provide<Counter>(
        builder: (BuildContext context, Widget child, Counter counter) {
            return Text(
                '${counter.value}',
                style: Theme.of(context).textTheme.display1,
            );
        },
    ),

     

    4. 发出通知

    接着就是发出通知了

    修改floatingActionButton的点击事件

    floatingActionButton: FloatingActionButton(
      onPressed: () => _counter.inc(),
      tooltip: 'Increment',
      child: Icon(Icons.add),
    ),

     

    这里调用第三步获取的那个Counter,然后调用inc方法


    看到这里,如果之前用过ScopedModel的朋友会问了,这个不是和以前一样吗,我为啥要改呢

    继续修改

    5. Stream模式

    这个就很类似于bloc了,只不过model不太一样

    添加一个StreamBuilder

    StreamBuilder<Counter>(
      initialData: _counter,
      stream: Provide.stream<Counter>(context),
      builder: (BuildContext context, AsyncSnapshot<Counter> snapshot) {
        return Text(
          '${snapshot.data.value}',
          style: Theme.of(context).textTheme.display1,
        );
      },
    ),

     

    这里initialData是第三步创建的那个,stream是使用Provide.stream<Counter>(context)获取的

    scope

    provide中有一个概念叫scope,类的完整类名叫ProviderScope

    class ProviderScope {
      final String _name;
    
      /// Constructor
      const ProviderScope(this._name);
    
      @override
      String toString() {
        return "Scope ('$_name')";
      }
    }

     

    这个类的作用就是标识Provider的区域,或者可以理解为给Provider/Provide定义一个作用区域

    只有scope相同的才可以识别

    将state的代码修改一下

    class _MyHomePageState extends State<MyHomePage> {
      Counter get _counter => Provide.value<Counter>(context);
    
      PageCounter pageCounter = PageCounter(0);
      PageCounter pageCounter2 = PageCounter(0);
      var scope1 = ProviderScope("1"); 
      var scope2 = ProviderScope("2");
      @override
      Widget build(BuildContext context) {
        return ProviderNode(
          providers: Providers()
            ..provide(Provider.value(pageCounter), scope: scope1)
            ..provide(Provider.value(pageCounter2), scope: scope2),
          child: Scaffold(
            appBar: AppBar(
              title: Text(widget.title),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'You have pushed the button this many times:',
                  ),
                  Provide<PageCounter>(
                    scope: scope1,
                    builder:
                        (BuildContext context, Widget child, PageCounter counter) {
                      return Text(
                        '${counter.value}',
                        style: Theme.of(context).textTheme.display1,
                      );
                    },
                  ),
                  Provide<PageCounter>(
                    scope: scope2,
                    builder:
                        (BuildContext context, Widget child, PageCounter counter) {
                      return Text(
                        '${counter.value}',
                        style: Theme.of(context).textTheme.display1,
                      );
                    },
                  ),
                  StreamBuilder<Counter>(
                    initialData: _counter,
                    stream: Provide.stream<Counter>(context),
                    builder:
                        (BuildContext context, AsyncSnapshot<Counter> snapshot) {
                      return Text(
                        '${snapshot.data.value}',
                        style: Theme.of(context).textTheme.display1,
                      );
                    },
                  ),
                  FlatButton(
                    child: Text("nextPage"),
                    onPressed: () {
                      Navigator.push(context,
                          MaterialPageRoute(builder: (BuildContext context) {
                        return MyHomePage(
                          title: "new page",
                        );
                      }));
                    },
                  ),
                ],
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                _counter.inc();
                pageCounter.inc();
                pageCounter2.rec();
              },
              tooltip: 'Increment',
              child: Icon(Icons.add),
            ),
          ),
        );
      }
    }

     

    这里定义了两个scope,并在Provide时进行了指定

    Provide<PageCounter>(
      scope: scope1,
      builder:
          (BuildContext context, Widget child, PageCounter counter) {
        return Text(
          '${counter.value}',
          style: Theme.of(context).textTheme.display1,
        );
      },
    ),

     

    这样只有当对应scope1的counter发出通知时,这里才会回调,这样就满足了一个页面/一个应用中有两个相同对象的识别问题

    后记

    这个插件托管在google仓库下,个人觉得应该是官方很推荐的一种状态管理模式

  • 相关阅读:
    oracle取字符串长度的函数length()和hengthb()
    kafka优化–JVM参数配置优化
    Linux 查看CPU信息,机器型号,内存等信息
    elasticsearch入库错误:gc overhead导致数据节点脱离集群
    揭密新一代运维管理平台建设七种利器
    EM12C 安装及卸载 注意点整理
    Tools:downloading and Building EDK II工具篇:安装/使用EDKII源代码获取/编译工具[2.3]
    【C语言探索之旅】 第二部分第十课:练习题和习作
    CSDN code使用教程之git使用方法具体解释
    [javase学习笔记]-7.5 构造函数须要注意的几个细节
  • 原文地址:https://www.cnblogs.com/stroll/p/10598670.html
Copyright © 2011-2022 走看看