Flutter中Provider 的使用例子

把Provider的测试过程记录一下

1. 创建一个flutter 工程,然后创建一个模型:CMyModel


class CMyModel extends ChangeNotifier{
  late int val;

  CMyModel(this.val){
    debugPrint('CMyModel:inited');
  }

  void inc(){
    val++;
    
    debugPrint('CMyModel:inc invoked');
    notifyListeners();
  }

  @override
  void dispose(){
    super.dispose();
    debugPrint('CMyModel:disposed');
  }
}

2. 把主类改写成如下:

        1. 增加了最上层的 MultiProvider,里面包含了 ChangeNotifierProvider,它暴露了上面写的类 CMyModel

        2. 增加了 getTitle() ,显示 CMyModel 中的值


class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    debugPrint('home build');
    return MultiProvider(providers: [
      ChangeNotifierProvider( create: (BuildContext context) => CMyModel(0))
    ],
      builder: (context,child){
        debugPrint('provider build');
          return Scaffold(
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  const Text('You have pushed the button this many times:'),
                  getTitle(context),
                ],
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: ()=>Provider.of<CMyModel>(context,listen: false).inc(),
              tooltip: 'Increment',
              child: const Icon(Icons.add),
            ),
          );
        }
    );
  }

  Widget getTitle(BuildContext context){
    debugPrint('get title build');
    return Text(
      '${Provider.of<CMyModel?>(context,listen: false)?.val}',
    );
  }
}

启动并点击按钮打印如下:

flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: CMyModel:inc invoked

没有刷新事件出现: 只是放在Provider中,并不会更新UI

我们可以用 Consumer 来让它刷新,具体不述。 我们换个方式 watch​​​​​​​ 来处理

3. 把 getTitle 改成如下:

  Widget getTitle(BuildContext context){
    debugPrint('get title build');
    return Text(
      '${context.watch<CMyModel>().val}',
    );
  }

启动并点击按钮打印如下:

flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: CMyModel:inc invoked
flutter: provider build
flutter: get title build

刷新事件出现了!需要显式的指明监控哪个对象

4. 添加一个新的类 CMyTitleWidget


class CMyTitleWidget extends StatefulWidget{
  const CMyTitleWidget({super.key});

  @override
  State<StatefulWidget> createState()=>_CMyTitleWidgetState();

}
class _CMyTitleWidgetState extends State<CMyTitleWidget>{
  @override
  Widget build(BuildContext context) {
    debugPrint('get title build');
    return Text(
      '${context.watch<CMyModel>().val}',
    );
  }
}

把 _MyHomePageState 中 build 函数的 getTitle(context) 替换成 CMyTitleWidget()

...
        body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: const <Widget>[
                  Text('You have pushed the button this many times:'),
                  CMyTitleWidget(),//!!!替换这一行
                ],
              ),
            ),
...

启动并点击按钮打印如下:

flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: CMyModel:inc invoked
flutter: get title build

刷新事件出现了!只会刷新发生变化的子树(向上的树结点不会刷新)

5. 把CMyModel改成如下:(增加一个新的属性:secVal)


class CMyModel extends ChangeNotifier{
  late int val;

  int secVal;

  CMyModel(this.val,{this.secVal = 100}){
    debugPrint('CMyModel:inited');
  }

  void inc(){
    val++;

    debugPrint('CMyModel:inc invoked');
    notifyListeners();
  }

  void secInc(){
    secVal += 2;

    debugPrint('CMyModel:secInc invoked');
    notifyListeners();
  }

  @override
  void dispose(){
    super.dispose();
    debugPrint('CMyModel:disposed');
  }
}

再创建一个新的类,用来显示它的值  secVal


class CMyTitleWidget2 extends StatefulWidget{
  const CMyTitleWidget2({super.key});

  @override
  State<StatefulWidget> createState()=>_CMyTitleWidgetState2();

}
class _CMyTitleWidgetState2 extends State<CMyTitleWidget2>{
  @override
  Widget build(BuildContext context) {
    debugPrint('get title build.2');
    return Text(
      '${context.watch<CMyModel>().secVal}',
    );
  }
}

把 _MyHomePageState 中 build 函数修改如下:

...
        body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: const <Widget>[
                  Text('You have pushed the button this many times:'),
                  CMyTitleWidget(),
                  CMyTitleWidget2(),
                ],
              ),
            ),
...

启动并运行,日志打印如下:

flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: get title build.2
flutter: CMyModel:inc invoked
flutter: get title build.2
flutter: get title build
flutter: CMyModel:secInc invoked
flutter: get title build.2
flutter: get title build

2个按钮点击后都会导致 CMyTitleWidget 与 CMyTitleWidget2 刷新。

其实我们不希望这样!

6. 把 CMyTitleWidget 改进一下,用 Selector 来包含一层,希望可以过滤其中的内容,改动如下:

class _CMyTitleWidgetState extends State<CMyTitleWidget> {
  @override
  Widget build(BuildContext context) {
    debugPrint('get title build');
    return Selector<CMyModel, int>(
      selector: (_, myModel) => myModel.val,
      builder: (_, val, child) {
        debugPrint('get title build.builder');
        return Text(val.toString());
      },
    );
  }
}

class _CMyTitleWidgetState2 extends State<CMyTitleWidget2>{
  @override
  Widget build(BuildContext context) {
    debugPrint('get title build.2');
    return Selector<CMyModel, int>(
      selector: (_, myModel) => myModel.secVal,
      builder: (_, val, child) {
        debugPrint('get title build.2.builder');
        return Text(val.toString());
      },
    );
  }
}

结果如下:

flutter: home build
flutter: provider build
flutter: get title build
flutter: CMyModel:inited
flutter: get title build.builder
flutter: get title build.2
flutter: get title build.2.builder
flutter: CMyModel:inc invoked
flutter: get title build.builder
flutter: CMyModel:secInc invoked
flutter: get title build.2.builder

只刷新我们预期的部分,完美!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值