Flutter _ 状态管理指南篇——Provider,思维导图+源代码+笔记+项目

本文详细介绍了Flutter的状态管理库Provider的使用,包括ValueBuilder、Disposer、何时选择不同类型的Provider,以及如何优雅处理多个Provider。强调了避免在build方法中产生副作用、避免全局状态过度使用、Model中使用私有变量的重要性,并探讨了Provider如何做到状态共享和控制刷新范围。此外,解答了关于数据初始化、性能优化和选择状态管理方案的常见问题。最后,简要分析了Flutter中的Builder模式和Provider的源码。
摘要由CSDN通过智能技术生成

selector: (context, provider) => provider.goodsList[index],
builder: (context, data, child) {
print((‘No.${index + 1} rebuild’));
},
);
},
);

ListView 这里就是使用了刚刚获取的 provider 中的 total 构建这个列表。然后列表中的每一个商品我们希望它根据自己的状态进行刷新,所以这时候就需要再次使用 Selector 来获取我们真正关心的那个 Good。

我们可以看到这里的 selector 返回了 provider.goodsList[index] 也就是具体的一个商品信息,所以每个商品只关注自己那部分信息,那么这个 Selector 的刷新范围就是 该商品。我们打印一下 rebuild 信息。

最后补上这个商品卡片的代码。

ListTile(
title: Text(data.goodsName),
trailing: GestureDetector(
onTap: () => provider.collect(index),
child: Icon(
data.isCollection ? Icons.star : Icons.star_border),
),
);

然后我们开始测试,点击收藏按钮,查看 rebuild 情况。

Performing hot reload…
Syncing files to device iPhone Xs Max…

flutter: No.8 rebuild
flutter: No.9 rebuild
flutter: No.10 rebuild
Reloaded 2 of 492 libraries in 446ms.
flutter: No.6 rebuild
flutter: No.1 rebuild

Cool! 现在只有我们当前收藏的这个 Selector 进行了 rebuild,避免了整个列表全部刷新。

你可以在这里查看该 Widget 的全部代码。

You also need to know

合理选择使用 Provides 的构造方法

在上面这个例子中👆,我们选择了使用 XProvider<T>.value 的构造方法来创建祖先节点中的 提供者。除了这种方式,我们还可以使用默认构造方法。

Provider({
Key key,
@required ValueBuilder builder,
Disposer dispose,
Widget child,
}) : this._(
key: key,
delegate: BuilderStateDelegate(builder, dispose: dispose),
updateShouldNotify: null,
child: child,
);

常规的 key/child 属性我们不在这里啰嗦。我们先来看这个看上去相对教复杂一点的 builder。

ValueBuilder

相比起 .value 构造方式中直接传入一个 value 就 ok,这里的 builder 要求我们传入一个 ValueBuilder。WTF?

typedef ValueBuilder<T> = T Function(BuildContext context);

其实很简单,就是传入一个 Function 返回一个数据而已。在上面这个例子中,你可以替换成这样。

Provider(
builder: (context) => textSize,

)

由于是 Builder 模式,这里默认需要传入 context,实际上我们的 Model(textSize)与 context 并没有关系,所以你完全可以这样写。

Provider(
builder: (_) => textSize,

)

Disposer

现在我们知道了 builder,那这个 dispose 方法又用来做什么的呢。实际上这才是 Provider 的点睛之笔。

typedef Disposer<T> = void Function(BuildContext context, T value);

dispose 属性需要一个 Disposer<T>,而这个其实也是一个回调。

如果你之前使用过 BLoC 的话,相信你肯定遇到过一个头疼的问题。我应该在什么时候释放资源呢? BloC 使用了观察者模式,它旨在替代 StatefulWidget。然而大量的流使用完毕之后必须 close 掉,以释放资源。

然而 Stateless Widget 并没有给我们类似于 dispose 之类的方法,这便是 BLoC 的硬伤。你不得不为了释放资源而使用 StatefulWidget,这与我们的本意相违。而 Provider 则为我们解决了这一点。

当 Provider 所在节点被移除的时候,它就会启动 Disposer<T>,然后我们便可以在这里释放资源。

举个例子,假如我们有这样一个 BLoC。

class ValidatorBLoC {
StreamController _validator = StreamController.broadcast();

get validator => _validator.stream;

validateAccount(String text) {
//Processing verification text …
}

dispose() {
_validator.close();
}
}

这时候我们想要在某个页面提供这个 BLoC 但是又不想使用 StatefulWidget。这时候我们可以在页面顶层套上这个 Provider。

Provider(
builder:() => ValidatorBLoC(),
dispose:(
, ValidatorBLoC bloc) => bloc.dispose(),
}
)

这样就完美解决了数据释放的问题!🤩

现在我们可以放心的结合 BLoC 一起使用了,很赞有没有。但是现在你可能又有疑问了,在使用 Provider 的时候,我应该选择哪种构造方法呢。

我的推荐是,简单模型就选择 Provider<T>.value,好处是可以精确控制刷新时机。而需要对资源进行释放处理等复杂模型的时候,Provider() 默认构造方式绝对是你的最佳选择。

其他几种 Provider 也遵循该模式,需要的时候可以自行查看源码。

我该使用哪种 Provider

如果你在 Provider 中提供了可监听对象(Listenable 或者 Stream)及其子类的话,那么你会得到下面这个异常警告。

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

你可以将本文中所使用到的 CounterModel 放入 Provider 进行提供(记得 hot restart 而不是 hot reload),那么你就能看到上面这个 Flutter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值