前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Flutter状态管理

Flutter状态管理

作者头像
flyou
发布于 2020-06-16 07:24:44
发布于 2020-06-16 07:24:44
1.7K00
代码可运行
举报
文章被收录于专栏:flutter开发者flutter开发者
运行总次数:0
代码可运行

在前面的文章中我们学习了Flutter中事件传递的方法,让我们可以在数据流向简单的业务场景中使用InheritedWidget、Notification 或者 EventBus。

但是随着业务逻辑的复杂,面对不同组件与不同页面之间的数据传递如果还使用前面讲到数据传递的方法就会显得异常繁琐,更会让页面的嵌套增多和数据流向的混乱,所以这个时候我们就需要有一种方案来管理我们需要跨界面传递的数据,于是便有了“状态管理”这个概念。

在前端开发中我们都会接触redux ,借助于redux 我们可以很轻松地完成多界面数据维护和获取,在Flutter中也有很多状态管理的第三方库,如Provider、Scoped Mode、flutter_redux、flutter_mobx 、BLoC、fish_redux等。

Provider作为官方推荐的状态管理工具具有使用简单和管理方便的特点,今天我们就先来看下Provider如何使用。

Provider实现原理

在前面的文章中我们学习过InheritedWidget的用法,通过对InheritedWidget的封装,使得Provider允许在 Widget 树中更加灵活地处理和传递数据。

Provider借助于ChangeNotifier实现发布者-订阅者模式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ChangeNotifier implements Listenable {
  List listeners=[];
  @override
  void addListener(VoidCallback listener) {
     //添加监听器
     listeners.add(listener);
  }
@override
void removeListener(VoidCallback listener) {
//移除监听器
    listeners.remove(listener);
  }
void notifyListeners() {
//通知所有监听器,触发监听器回调
    listeners.forEach((item)=>item());
  }

  ...
}

具体的细节我们不再具体去探讨,今天就来看看如何使用。

首先,我们假定这样一个场景,第一个界面显示用户的昵称,然后我们在第二个界面修改昵称再返回观察第一个界面的显示情况。

首先我们建立一个用户信息操作类UserInfoModel使它继承ChangeNotifier

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class UserInfoModel with ChangeNotifier {
  String _nickName = "userName";
  // 读方法
Stringget nickName => _nickName;
// 写方法
void updateNickName(String nickName) {
    _nickName=nickName;
    notifyListeners();// 通知听众刷新
  }
}
数据更新

可以看到我们在UserInfoModel中定义了_nickName属性并设置相关获取与设置属性的方法,在设置属性方法中我们通过notifyListeners方法告知数据刷新。

因为Provider 是InheritedWidget实现的,所以数据也是有流向的,所以我们需要把ChangeNotifierProvider.value放在两个界面上面的位置,这样我们一旦更新一个页面的数据另外一个页面就也可以获取到。

首先,我们定一个入口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void main() {
  runApp(new MaterialApp(
    home:   MyApp(),
  ));
}

然后定义入口Widget

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
        value: UserInfoModel(),
        child: MaterialApp(
          home: FirstPage(),
        )
    );
  }
}

第一个界面我们定义一个按钮和一个Text用来显示第二个界面更新的数据

我们使用context.watch()方法来获取到对象,并监听

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("ProviderTitle"),
      ),
      body: Center(
        child: Column(
          children: [
            Text( context.watch<UserInfoModel>().nickName),
            RaisedButton(
              child: Text("去设置界面"),
              onPressed: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return SecondPage();
                }));
              },
            )
          ],
        ),
      ),
    );
  }
}

第二个界面我们定义一个输入框和一个按钮,点击按钮就把输入框的值设置给Provider

我们使用 Provider.of(context)方法来获取监听对象并进行修改操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    TextEditingController _unameController = TextEditingController();
  var userModel=  Provider.of<UserInfoModel>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text("ProviderTitle"),
      ),
      body: Column(
        children: [
          TextField(
            autofocus: true,
            controller: _unameController,
            decoration: InputDecoration(
                labelText: "用户名",
                hintText: "用户名或邮箱",
                prefixIcon: Icon(Icons.person)),
          ),
          RaisedButton(
            onPressed: () {
              userModel.updateNickName(_unameController.text);

            },
            child: Text("设置"),
          )
        ],
      ),
    );
  }
}
同时管理多个数据

在上面我们介绍了如何通过Provider来管理用户名数据,那么如果涉及多个数据我们该如何来管理呢?

通常情况下我们可以把多个数据封装成一个完整的数据来进行操作,这种方法在数据间相互关联性比较接近的情况下是可以实现的,但是如何遇到数据关系不大的情况下还采用这种方法的话就会造成界面Widget不必要的重绘。

当然,Provider也为我们提供了解决方法,MultiProvider可以让我们同时管理多个数据。

还是以上面的例子来进行说明,我们在前面用户名的基础上又增加了一个“家庭地址”,在第一个界面新增一个Text用来显示家庭地址,在第二个界面新增一个输入框用来输入家庭地址。

首先我们定义一个用来管理地址的Model

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class UserLocationModel with ChangeNotifier {
  String _address = "address";

  // 读方法
Stringget address => _address;

// 写方法
void setAddress(String address) {
    _address = address;
    notifyListeners(); // 通知听众刷新
  }
}

然后我们使用MultiProvider来管理多个Model

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 通过 Provider 组件封装数据资源
return MultiProvider(providers: [
      ChangeNotifierProvider.value(value: UserInfoModel()),
      ChangeNotifierProvider.value(value: UserLocationModel())
    ], child: MaterialApp(home: FirstPage()));
  }
}

然后在第一个界面接收并显示数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ProviderTitle"),
      ),
      body: Center(
        child: Column(
          children: [
            Text("用户名:${context.watch<UserInfoModel>().nickName}"),
            Text("家庭地址:${context.watch<UserLocationModel>().address}"),
            RaisedButton(
              child: Text("去设置界面"),
              onPressed: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return SecondPage();
                }));
              },
            )
          ],
        ),
      ),
    );
  }
}

在第二个界面设置数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    TextEditingController _unameController = TextEditingController();
    TextEditingController _homeController = TextEditingController();
    var userModel = Provider.of<UserInfoModel>(context);
    var homeModel = Provider.of<UserLocationModel>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text("ProviderTitle"),
      ),
      body: Column(
        children: [
          TextField(
            autofocus: true,
            controller: _unameController,
            decoration: InputDecoration(
                labelText: "用户名",
                hintText: "用户名或邮箱",
                prefixIcon: Icon(Icons.person)),
          ),

          RaisedButton(
            onPressed: () {
                userModel.updateNickName(_unameController.text);
            },
            child: Text("设置用户名"),
          ),
          TextField(
            autofocus: true,
            controller: _homeController,
            decoration: InputDecoration(
                labelText: "家庭地址",
                hintText: "请输入家庭地址",
                prefixIcon: Icon(Icons.person)),
          ),
          RaisedButton(
            onPressed: () {
            homeModel.setAddress(_homeController.text);

            },
            child: Text("设置家庭地址"),
          ),

        ],
      ),
    );
  }
}

当然我们也可以使用Consumer2方法来获取多个数据的传递,这样就不需要再创建UserInfoModel和UserLocationModel了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ProviderTitle"),
      ),
      body: Center(
          child: Consumer2<UserInfoModel, UserLocationModel>(
//builder 函数以参数的形式提供了数据资源
              builder: (context, UserInfoModel userInfoModel,
                      UserLocationModel userLocationModel, _) =>
                  Column(
                    children: [
                      Text("用户名:${userInfoModel.nickName}"),
                      Text("家庭地址:${userLocationModel.address}"),
                      RaisedButton(
                        child: Text("去设置界面"),
                        onPressed: () {
                          Navigator.push(context,
                              MaterialPageRoute(builder: (context) {
                            return SecondPage();
                          }));
                        },
                      )
                    ],
                  ))),
    );
  }
}

小结

  • Provider是对InheritedWidget的封装方便我们在多个界面间传递数据
  • Provider支持同时管理多个数据的状态
  • 可以借助与Consumer-Consumer6方法来管理多个数据状态
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 flutter开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
flutter如何进行状态管理
在flutter中,如果我们的应用足够简单,数据流动的方向和顺序是清晰的,我们只需要将数据映射成视图就可以了。作为声明式的框架,Flutter 可以自动处理数据到渲染的全过程,通常并不需要状态管理。
挥刀北上
2021/01/16
1.6K0
flutter如何进行状态管理
优化 Flutter 应用开发:探索 ViewModel 的威力
ViewModel,顾名思义,就是视图的模型。在 Flutter 中,ViewModel 是一种用于管理视图状态和业务逻辑的重要概念。它承载了应用程序的核心功能,像是一个精心设计的控制中心,负责连接视图和数据模型,使得应用程序能够顺畅地运行。
繁依Fanyi
2024/04/23
5230
Flutter Provider 使用指南详解
在Flutter应用程序开发中,状态管理是一个至关重要的方面。随着应用程序的复杂性增加,有效地管理和共享状态变得至关重要。Flutter Provider是一个流行的状态管理解决方案,它提供了一种简单而强大的方式来管理Flutter应用程序中的状态。
繁依Fanyi
2024/03/26
2.1K0
Flutter —— 状态管理 | Provide
有关Provide的题外话,Provide 是 ScopedModel 的进阶或者说是兄弟,为何这么说呢?因为这两个插件的内容重叠的太多,所以对于这两个插件存在争议。
CatEatFish
2020/07/09
1.6K0
Flutter&鸿蒙next 状态管理高级使用:深入探讨 Provider
在 Flutter 开发中,状态管理是一个至关重要的主题。Flutter 提供了多种状态管理方案,其中 Provider 是最流行和灵活的选择之一。本文将深入探讨 Provider 的高级用法,以帮助开发者更好地理解和应用这一强大的状态管理工具。
淼学派对
2024/11/04
1240
Flutter完整开发实战详解(十五、全面理解State与Provider)
本篇将带你深入理解 Flutter 中 State 的工作机制,并通过对状态管理框架 Provider 解析加深理解,看完这一篇你将更轻松的理解你的 “State 大后宫” 。
GSYTech
2019/06/17
3.8K0
【Flutter 专题】46 图解新的状态管理 Provider (一)
2019 Google I/O 大会上重磅消息出了支持 flutter_web 之外,另一个便是弃用之前的状态管理 Provide,转而推荐相似的库 Provider;虽然只有一个字母之差使用方式差别却很大;和尚初步学习一下新的状态管理库 Provider;
阿策小和尚
2019/08/12
2.1K0
【Flutter 专题】46 图解新的状态管理 Provider (一)
FlutterDojo设计之道—状态管理之路(六)
其实前面讲了这么多,最后的结论依然是——Provider真香。这毕竟是官方推荐的状态管理方案,就目前而言,绝大部分的场景都可以使用Provider来进行状态管理,同时也基本上是最佳方案。
用户1907613
2020/09/17
9740
Flutter状态管理(1)——InheritedWidget
局部状态:根据官方的含义,就是一个StatefulWidget可以搞定的,比如BottomNavigationBar、PageView等等,其他Widget不需要知道你的状态,你也不需要依赖其他Widget的状态;setState可以实现状态的切换; 全局状态:整个app很多页面都需要用到的状态,比如是否登录了,用户名、用户id等;这个的实现有很多方式,可以参考List of state management approaches
用户1108631
2019/09/17
1.2K0
Flutter状态管理(1)——InheritedWidget
【Flutter 技能篇】你不得不会的状态管理 Provider
本文首发于政采云前端团队博客:【Flutter 技能篇】你不得不会的状态管理 Provider https://www.zoo.team/article/flutter-and-provider
政采云前端团队
2021/01/28
4K0
【源码篇】Flutter Provider的另一面(万字图文+插件)
此事说来话短,我这不准备写解析Provider源码的文章,肯定要写这框架的使用样例啊,然后再哔哔源码呀!在写demo样例的时候,新建那俩三个文件、文件夹和必写的模板代码,这让我感到很方啊,这不耽误我时间嘛!然后就撸了这个插件,相对而言,多花了几百倍的时间。。。
小呆呆666
2021/05/31
1.5K1
《深入浅出Dart》状态管理
在应用程序开发中,状态管理是一项重要的任务,用于管理应用程序的数据和状态。状态管理的目标是确保应用程序的不同部分能够共享和响应相同的数据,并保持数据的一致性和更新。
linwu
2023/07/27
2900
Flutter Provider状态管理---八种提供者使用分析
在我们上一篇文章中对Provider进行了介绍以及类结构的说明,最后还写了一个简单的示例,通过上一章节我们对Provider有了一个基本的了解,这一章节我们来说说Provider的8种提供者以及他们的使用区别。
玖柒的小窝
2021/10/06
4.4K0
Flutter Provider状态管理---八种提供者使用分析
【Flutter 专题】47 图解新的状态管理 Provider (二)
和尚前几天学习了一下新的状态管理框架 Provider,Provier 支持多种类型的状态管理方式,和尚继续学习其余几种;
阿策小和尚
2019/08/12
1.6K0
【Flutter 专题】47 图解新的状态管理 Provider (二)
Flutter 的状态管理方案:setState、BLoC、ValueNotifier、Provider
登录页面的主要导航是通过一个小部件实现的,该小部件使用 Drawer 菜单在不同选项中进行选择。
玖柒的小窝
2021/11/28
5K0
Flutter 的状态管理方案:setState、BLoC、ValueNotifier、Provider
Flutter如何状态管理
- fluter Utils 工具类库:https://github.com/yangchong211/YCFlutterUtils
杨充
2021/08/19
1.2K0
[- Flutter-技能篇 -] 使用Provider前你应了解Consumer
Flutter的状态管理三足鼎立,明媒正室当Provider莫属,可谓刘备级别的大佬,名正言顺。作为一个喜欢偷懒的人,能省则省。都知道Provider有一把梭,打遍天下无敌手。不过刷这两招,可要悠着点,否则代价就是性能。 Provider.of<XXX>(context).数据 Provider.of<XXX>(context).方法 ---- 一、一把梭 页面如下,第一个界面是四个色块,点击蓝色字时跳到紫色界面 这里进行了五次操作:状态同步实现,貌似表面上完美无瑕,而且一把梭就OK了,也很方便,BUT
张风捷特烈
2020/04/30
2.9K0
[- Flutter-技能篇 -] 使用Provider前你应了解Consumer
Flutter状态管理新的实践
Tech 导读 本文介绍flutter端状态刷新的一种新的思路和尝试,通过dart的扩展属性,定义一个观察者模式,去更新widget的状态,以及如何在widget的生命周期寻找一个切入点,建立订阅关系。
京东技术
2022/09/27
1.2K0
Flutter状态管理新的实践
【Flutter 专题】57 图解页面小跳转 (三)
和尚在去年刚接触 Flutter 时学习了一下页面跳转路由的基本用法,随着逐渐的学习和场景的使用,对一些特殊场景下路由使用进行尝试;
阿策小和尚
2019/08/22
1.7K0
【Flutter 专题】57 图解页面小跳转 (三)
flutter鸿蒙版本mvvm架构思想原理
在Flutter中实现MVVM(Model-View-ViewModel)架构是为了将UI(视图)与业务逻辑(模型和视图模型)分离,提高代码的可维护性和可读性。
淼学派对
2024/11/04
1660
推荐阅读
相关推荐
flutter如何进行状态管理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档