Flutter _ 状态管理指南篇——Provider,Android权限处理

本文详细介绍了Flutter中的Provider状态管理,包括Single Model Consumer、Consumer2、Selector的使用,以及如何优雅地处理多个Provider。同时,文章提到了Android权限处理的重要性,并提醒开发者注意在build方法中避免副作用,合理控制刷新范围,确保良好的性能表现。
摘要由CSDN通过智能技术生成

在这个页面中,我们有两处使用到了公共 Model。

  • 应用中心的文字:使用 CounterModel 在 Text 中展示文字,以及通过 textSize 定义自身的大小。一共使用到了两个 Model。
  • 浮动按钮:使用 CounterModel 的 increment 方法触发计数器的值增加。使用到了一个 Model。
Single Model Consumer

我们先看 floatingActionButton,使用了一个 Consumer 的情况。

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

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

  • context: context 就是 build 方法传进来的 BuildContext 在这里就不细说了,如果有兴趣可以看我之前这篇文章 Flutter | 深入理解BuildContext
  • T:T也很简单,就是获取到的最近一个祖先节点中的数据模型。
  • child:它用来构建那些与 Model 无关的部分,在多次运行 builder 中,child 不会进行重建。

然后它会返回一个通过这三个参数映射的 Widget 用于构建自身。

在这个浮动按钮的例子中,我们通过 Consumer 获取到了顶层的 CounterModel 实例。并在浮动按钮 onTap 的 callback 中调用其 increment 方法。

而且我们成功抽离出 Consumer 中不变的部分,也就是浮动按钮中心的 Icon 并将其作为 child 参数传入 builder 方法中。

Consumer2

现在我们再来看中心的文字部分。这时候你可能会有疑惑了,刚才我们讲的 Consumer 获取的只有一个 Model,而现在 Text 组件不仅需要 CounterModel 用以显示计数器,而且还需要获得 textSize 以调整字体大小,咋整捏。

遇到这种情况你可以使用 Consumer2<A,B>。使用方式基本上和 Consumer<T> 一致,只不过范型改为了两个,并且 builder 方法也变成了 Function(BuildContext context, A value, B value2, Widget child)

我勒个去…假如我要获得 100 个 Model,那岂不是得搞个 Consumer100 (???黑人问号.jpg)

然而并没有 😏。

从源码里面可以看到,作者只为我们搞到了 Consumer6。emmmmm…还要要求更多就只有自力更生喽。

顺手帮作者修复了一个 clerical error。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

区别

我们来看 Consumer 的内部实现。

@override
Widget build(BuildContext context) {
return builder(
context,
Provider.of(context),
child,
);
}

可以发现,Consumer 就是通过 Provider.of<T>(context) 来实现的。但是从实现来讲 Provider.of<T>(context)Consumer 简单好用太多,为啥我要搞得那么复杂捏。

实际上 Consumer 非常有用,它的经典之处在于能够在复杂项目中,极大地缩小你的控件刷新范围Provider.of<T>(context) 将会把调用了该方法的 context 作为听众,并在 notifyListeners 的时候通知其刷新。

举个例子来说,我们的 FirstScreen 使用了 Provider.of<T>(context) 来获取数据,SecondScreen 则没有。

  • 你在 FirstScreen 中的 build 方法中添加一个 print('first screen rebuild');
  • 然后在 SecondScreen 中的 build 方法中添加一个 print('second screen rebuild');
  • 点击第二个页面的浮动按钮,那么你会在控制台看到这句输出。

first screen rebuild

首先这证明了 Provider.of<T>(context) 会导致调用的 context 页面范围的刷新。

那么第二个页面刷新没有呢? 刷新了,但是只刷新了 Consumer 的部分,甚至连浮动按钮中的 Icon 的不刷新我们都给控制了。你可以在 Consumer 的 builder 方法中验证,这里不再啰嗦

假如你在你的应用的 页面级别 的 Widget 中,使用了 Provider.of<T>(context)。会导致什么后果已经显而易见了,每当其状态改变的时候,你都会重新刷新整个页面。虽然你有 Flutter 的自动优化算法给你撑腰,但你肯定无法获得最好的性能

所以在这里我建议各位尽量使用 Consumer 而不是 Provider.of<T>(context) 获取顶层数据。

以上便是一个最简单的使用 Provider 的例子。

Selector

如果你使用 Provider 到实际项目中,很容易遇到这样一个情况。如果按照业务来分 Provider 的话,一个 Provider 可能会为多个控件提供不同的数据。比如我们在电商类应用中,把商品作为一个 Provider 来提供,这时候通常是服务器返回了一个 Goods 的 List Json,我们需要提供整个 GoodsList 的数据供展示。而这时候如果我们有一个属性是收藏,每个商品都可以单独收藏。这时候我们想要收藏一个商品,收藏完毕之后必然会需要通知界面刷新,那么就 notifyListeners,这时候如果不加处理的话,所有依赖于这个 Provider 的 Goods 都会刷新,也就是全列表范围的刷新,这一定不是我们想要的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那么我们很自然的容易想到,是否还可以过滤掉无用更新呢?

所以针对这个问题,在 Provider 3.1 版本中推出了 Selector Widget,进一步强化 Consumer 的功能。

这里我们就来简单实现一个商品列表的样例。

class GoodsListProvider with ChangeNot

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值