04_Provider基本使用

状态管理

在 Flutter 开发中,状态管理是一个永恒的话题。一般的原则是:如果状态是组件私有的,则应该由组件自己管理;如果状态要跨组件共享,则该状态应该由各个组件共同的父元素来管理。对于组件私有的状态管理很好理解,但对于跨组件共享的状态,管理的方式就比较多了,如使用全局事件总线EventBus,它是一个观察者模式的实现,通过它就可以实现跨组件状态同步:状态持有方(发布者)负责更新、发布状态,状态使用方(观察者)监听状态改变事件来执行一些操作。(转自:Flutter实战.第二版 7.3章节)

provider

provider是flutter官方提供的状态管理widget。使用provider客户管理的数据,可以提供给子孙节点使用。

举例

1、引入库

...
# 状态管理
  provider: ^6.0.1
...

2、创建数据model

数据源:

  • 一个CountModel类,混合ChangeNotifier。
  • 一个count变量,用于计数,
  • 一个increase方法调用一次则count+1,并调用notify方法
import 'package:flutter/cupertino.dart';

class CountModel with ChangeNotifier{
  int _count=0;

  int get count => _count;
  //修改数据,并调用notify方法
  void increase(){
    _count++;
    //修改数据后调用notify方法
    notifyListeners();
  }
}

3、创建全局共享数据

ChangeNotifierProvider.value 可以提供数据供子孙节点使用,并且可以在数据改变的时候通知所有子节点刷新。

  • 创建数据countModel
  • 创建ChangeNotifierProvider对象,把countModel传给value,让其子节点都可以访问到。并把MyApp传给child
void main() {
//防止报错
  WidgetsFlutterBinding.ensureInitialized();
  Provider.debugCheckInvalidValueType = null;
  //全局数据
  var countModel = CountModel();
  var textSize = 12;
  //只要是当前provider下的子节点都可以使用countModel变量
  var provider = ChangeNotifierProvider<CountModel>.value(
    value: countModel,
    child: MyApp(),
  );
  
  runApp(provider);
}

4、子节点处理数据

  • Provider.of获取到顶层数据
  • 点击按钮会调用countModel.increase()方法,里面又调用notifyListeners()方法
  • notifyListeners()通过provider会调用build方法即去更新UI。
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    var countModel = Provider.of<CountModel>(context);
    print('countModel:${countModel.hashCode}');
    print('count:${countModel.count}');
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("状态管理")),
        body: Column(
          children: [
            Text("计数${countModel.count}"),
            RaisedButton(
              onPressed: () {
                countModel.increase();
              },
              child: Text("增加"),
            )
          ],
        ),
      ),
    );
  }
}

log输出

Performing hot reload...
Syncing files to device Android SDK built for x86...
I/flutter (  811): countModel:895566778
I/flutter (  811): count:3
Reloaded 0 libraries in 955ms.
I/flutter (  811): countModel:895566778
I/flutter (  811): count:4

界面就不演示了

扩展

多个子节点

新增一个FirstPage页面

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var countModel = Provider.of<CountModel>(context);
    // var textSize = Provider.of<int>(context);

    return Scaffold(
      backgroundColor: Colors.amber,
      appBar: AppBar(
        title: Text("firstPage"),
      ),
      body: Center(
        child: Text("count:${countModel.count}"),
      ),
    );
  }
}

MyApp

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    var countModel = Provider.of<CountModel>(context);
    print('countModel:${countModel.hashCode}');
    print('count:${countModel.count}');
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("状态管理")),
        body: Column(
          children: [
            Text("计数${countModel.count}"),
            RaisedButton(
              onPressed: () {
                countModel.increase();
              },
              child: Text("增加"),
            ),
            Expanded(child: FirstPage())//添加firstPage
          ],
        ),
      ),
    );
  }
}

当点击增加按钮,myapp页面和firstpage页面的数据同时更新
效果
image

使用Consumer

Consumer 使用了 Builder 模式,收到更新通知就会通过 builder 重新构建。Consumer 代表了它要获取哪一个祖先中的 Model。

Consumer 的 builder 实际上就是一个 Function,它接收三个参数 (BuildContext context, T model, Widget child)。

  • context: context 就是 build 方法传进来的 BuildContext
  • T:T也很简单,就是获取到的最近一个祖先节点中的数据模型。
  • child:它用来构建那些与 Model 无关的部分,在多次运行 builder 中,child 不会进行重建。

然后它会返回一个通过这三个参数映射的 Widget 用于构建自身。
在这个浮动按钮的例子中,我们通过 Consumer 获取到了顶层的 CounterModel 实例。并在浮动按钮 RaisedButton 的 onPressed 中调用其 increase 方法。
而且抽离出Consumer中不变的部分,也就是控件Text(“不变的widget222”,style: TextStyle(color: Colors.red)其作为 child 参数传入 builder 方法中。

//第二页
class TwoPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TwoPage Page'),
      ),
      body: Consumer<CountModel>(
        builder: (context, CountModel counter, child) => Center(
          child: Text(
            '可变的widget,计数: ${counter.count}',//重新定义了一个新widget修改数据
          ),
        ),
        child: Text('不变的widget'),
      ),
      floatingActionButton: Consumer<CountModel>(
        builder: (context, CountModel counter, child) => RaisedButton(
          onPressed: () {
            counter.increase();
          },
          child: child,//这里传过去的是控件:不变的widget222
        ),
        child: Text(
          "不变的widget222",
          style: TextStyle(color: Colors.red),
        ),
      ),
    );
  }
}

跳转至第二页

//第一页
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var countModel = Provider.of<CountModel>(context);
    // var textSize = Provider.of<int>(context);

    return Scaffold(
      backgroundColor: Colors.amber,
      appBar: AppBar(
        title: Text("firstPage"),
      ),
      body: Center(
        child: Text("count:${countModel.count}"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(context).push(MaterialPageRoute(builder: (context) => TwoPage()));
        },
        child: Icon(Icons.navigate_next),
      ),
    );
  }
}

效果
image

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值