前端开发进阶篇——Flutter状态管理Provider

举报
小团子999 发表于 2020/07/19 14:52:18 2020/07/19
【摘要】 Flutter状态管理Provider

1. 为什么需要状态管理

        我们都知道一个应用程序随着功能的增加,将会有几十个页面,应用需要共享多处统一状态。如果一个页面状态更新,我们需要在多个页面进行状态同步更新。Flutter 其实就为我们提供了一种状态管理方式StatefulWidget,然而它仅仅适合用于在单个 Widget 内部维护其状态。当我们需要使用跨组件的状态时,StatefulWidget 将不再是一个好的选择,所以我们需要引用Provider插件,它是flutter官方推荐的状态管理方式。

2. Provider分类

  • Provider

        一个Provider,通过委派一对Create和Dispose来管理维护所提供的状态值的生命周期。

        它的构造方法是:Provider({Key key, @required Create<T> create, Dispose<T> dispose, bool lazy, TransitionBuilder builder, Widget child})。

        其中Create<T> 方法是必须有的,用来创建所以侦听的对象。Dispose<T>用来销毁侦听对象。

  • ListenableProvider

  • ChangeNotifierProvider

        是ChangeNotifier的子类,通常我们使用的是ChangeNotifierProvider 。ChangeNotifierProvider能够对子节点提供一个继承 、 混入、 实现 了 ChangeNotifier 的Model类。我们只需要在需要侦听的Model类 中 with ChangeNotifier ,然后在需要刷新状态的位置调用 notifyListeners ()即可。

  • ValueListenableProvider

        ValueListenableProvider 用于提供实现了 继承、混入、实现 了 ValueListenable 的 Model类。是专门用于处理只有一个单一变化数据的 ChangeNotifier。
通过 ValueListenable 处理的Model类不再需要数据更新的时候调用 notifyListeners()。

  • StreamProvider

        StreamProvider 专门用作提供(provide)侦听Stream,将其内容公开给child后代。它的主要用于是向大量窗口小部件提供Stream的内容。

  • FutureProvider

        侦听Future组件,提供了一个 Future 给其子孙节点,并在 Future 完成时,通知依赖的子孙节点进行刷新。

3. Provider实战

  • 主题切换功能

        我们首先创建我们需要侦听状态的Model类,它不仅储存了我们的数据模型,而且还包含了更改数据的方法,并暴露出它想要暴露出的数据。这里我们让ThemelModel类混入了ChangeNotifier。我们在执行_update()方法时,调用 notifyListeners() 时,它会通知所有听众进行刷新。其代码如下:

    import 'package:flutter/material.dart';
   
    class ThemeModel with ChangeNotifier {
      ThemeData themeData;
      ThemeType currentType;
    
      ThemeModel(ThemeType type) {
        currentType = type;
        if (type == ThemeType.dark) {
          themeData = ThemeData.dark();
        } else {
          themeData = ThemeData.light();
        }
      }
    
      void reverse() {
        if (currentType == ThemeType.light) {
          _update(ThemeType.dark);
        } else {
          _update(ThemeType.light);
        }
      }
    
      void _update(ThemeType type) {
        currentType = type;
        if (type == ThemeType.light) {
          themeData = ThemeData.light();
        } else {
          themeData = ThemeData.dark();
        }
        notifyListeners();
      }
    }
    
    enum ThemeType { 
        light,
        dark, 
        red 
        }

        接下来我们在 main 方法中注入监听全局数据ThemeModel类:

            ChangeNotifierProvider<ThemeModel>(

                create: (_) {

                    return ThemeModel(ThemeType.light);

                },

         ChangeNotifierProvider<ThemeModel>不仅能够提供数据供子孙节点使用,还可以在数据改变的时候通知所有听众刷新。

    最后我们点击按钮操作事件,调用Provider.of<T>(context)来获取ThemeModel类reverse()方法,修改应用的主题模式,当主题发生改变时,并通过 Consumer<ThemeModel>获取数据状态改变修改模式提示字。关键代码如下:

        FlatButton(
              child: Consumer<ThemeModel>(builder: (context, value, child) {
                String result = '';
                if (value.currentType == ThemeType.dark) {
                  result = '白天模式';
                } else {
                  result = '夜间模式';
                }
                return Text(result);
              }),
              onPressed: () {
                Provider.of<ThemeModel>(context, listen: false).reverse();
              },
            )

运行截图如下(点击按钮可以实现夜间模式和白天模式互换):

            

  • 商城菜单联动功能

        我们需要实现通过点击左侧菜单栏,实现右上方子类的状态的修改,具体截图如下:

图片.png


        首先我们还是需要创建我们需要侦听状态的Model类

        class ChildCategory with ChangeNotifier {
          List<CategoryGood> childCategoryList = [];
        
          getChildCategory(List<CategoryGood> list) {
            // childCategoryList = list;
            CategoryGood all = CategoryGood();
            all.categoryId = 00;
            all.goodId = '00';
            all.goodName = '全部';
            childCategoryList = [all];
            childCategoryList.addAll(list);
            notifyListeners();
          }
        }

        在主入口文件main函数中注入监听Model类,这次我们使用了ListenableProvider。

        void  main() {
              runApp(ListenableProvider<ChildCategory>(
                  create: (_) => ChildCategory(), child: MyApp()));
        }

        当我们从后台获取到商品分类时,第一次调用 Provider.of<ChildCategory>(context, listen: false).getChildCategory(list[0].categoryGood);初始化加载后左侧菜单栏显示。

        void _getCategory() async {
            await request('CategoriesContent').then((value) {
              var data = json.decode(value.toString());
              print(data);
              CategoryModel category = CategoryModel.fromJson(data);
              setState(() {
                list = category.data;
              });
              Provider.of<ChildCategory>(context, listen: false)
                  .getChildCategory(list[0].categoryGood);
            });
          }

        接下来我们需要在InkWell组件的onTap()方法中,实现通过点击左侧菜单,实现将其子类数据传递给监听Model类的getChildCategory( List <CategoryGood>  list)方法,实现左侧子菜单数据的更新

        onTap: () {
        setState(() {
          listIndex = index;
        });
        var childList = list[index].categoryGood;
        Provider.of<ChildCategory>(context, listen: false)
            .getChildCategory(childList);
      },

        然后我们通过Provider.of<ChildCategory>(context, listen: true).childCategoryList[index])获取更新完后左侧子菜单数据。

        ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: Provider.of<ChildCategory>(context, listen: true)
                  .childCategoryList
                  .length,
              itemBuilder: (context, index) {
                // print(Provider.of<ChildCategory>(context, listen: true)
                //     .childCategoryList[index]);
                return _rightInkwel(
                    Provider.of<ChildCategory>(context, listen: true)
                        .childCategoryList[index]);
              },
            )

        以上是我在实践中用到的Provider实现的状态管理的例子,还在学习中,如有错误,请批评指正!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200