今天偶然发如今谷歌爸爸的仓库下出现了一个叫作flutter-provide的状态管理框架,2月8日才第一次提交,很是新鲜。在简单上手以后感受就是一个字——爽!因此今天就跟你们分享一下这个新的状态管理框架。git
Provider被设计为ScopedModel的替代品,而且容许咱们更加灵活地处理数据类型和数据。可是首先呢仍是先说说老生常谈的状态管理。github
在咱们一开始构建应用的时候,也许很简单。咱们有一些状态,直接把他们映射成视图就能够了。这种简单应用可能并不须要状态管理。redux
可是随着功能的增长,你的应用程序将会有几十个甚至上百个状态。这个时候你的应用应该会是这样。架构
Wow,这是什么鬼。咱们很难再清楚的测试维护咱们的状态,由于它看上去实在是太复杂了!并且还会有多个页面共享同一个状态,例如当你进入一个文章点赞,退出到外部缩略展现的时候,外部也须要显示点赞数,这时候就须要同步这两个状态。app
这时候,咱们便迫切的须要一个架构来帮助咱们理清这些关系,状态管理框架应运而生。框架
和Scoped_model同样,Provide也是借助了InheritWidget,将共享状态放到顶层MaterialApp之上。底层部件经过Provier获取该状态,并经过混合ChangeNotifier通知依赖于该状态的组件刷新。异步
Provide还提供了Provide.stream,让咱们可以以处理流的方式处理数据,不过目前还有一些问题,不推荐使用。ide
咱们这里仍是以一个简单app为例,详细介绍Provide的用法。其中涉及共享状态以及多个状态之间如何管理。post
这两个页面都同时依赖于counter 和 switcher两个不一样的状态。而且一个页面改变状态以后另一个页面状态也随之改变。性能
该项目完整代码已放在 Github
在pubspec.yaml中添加Provide的依赖。
这里实际上它承担了State的职责,可是为了和官方的State区分因此叫作model。
import 'package:flutter/material.dart'; class Counter with ChangeNotifier{ int value = 0; increment(){ value++; notifyListeners(); } }
这里咱们能够看到,数据和操做数据的方法都在model中,咱们能够很清晰的把业务分离出来。
对比Scoped_model能够发现,Provide模式中model再也不须要继承Model类,只须要实现Listenable,咱们这里混入ChangeNotifier,能够不用管理听众。
经过 notifyListeners 咱们能够通知听众刷新。
void main() { var counter = Counter(); var providers = Providers(); //将counter对象添加进providers providers.provide(Provider<Counter>.value(counter)); runApp( ProviderNode( child: MyApp(), providers: providers), ); }
ProviderNode封装了InheritWidget,而且提供了 一个providers容器用于放置状态。
ProviderScope 为Provider提供单独的类型空间,它容许多个相同类型的提供者。默认使用ProviderScope('_default'),存放的时候你能够经过ProviderScope("name")来指定key。
添加一组Provider的时候建议使用provideFrom或者provide方法,而不是provideAll,由于它能够检查编译时的类型错误。
Provider<Counter>.value将counter包装成了_ValueProvider。并在它的内部提供了StreamController从而实现对数据进行流式操做。
一样的Provide也提供了两种获取State的方法。咱们先来介绍第一种,经过Provide<T>小部件获取。
Provide<Counter>( builder: (context, child, counter) { return Text( '${counter.value}', style: Theme.of(context).textTheme.display1, ); }, ),
每次通知数据刷新时,builder将会从新构建这个小部件。
builder方法接收三个参数,这里主要介绍第二个和第三个。
scope:经过指定ProviderScope获取该键所对应的状态。在须要使用多个相同类型状态的时候使用。
第二种获取方式:Provide.value<T>(context)
final currentCounter = Provide.value<Counter>(context);
这种方式实际上调用了context.inheritFromWidgetOfExactType找到顶层的_InheritedProviders来获取到顶层providers中的状态。
和scoped_model不一样的是,provide模式中你能够轻松组织多个状态。只须要将状态provide进provider中就能够了。
void main() { var counter = Counter(); var switcher = Switcher(); var providers = Providers(); providers ..provide(Provider<Counter>.value(counter)) ..provide(Provider<Switcher>.value(switcher)); runApp( ProviderNode( child: MyApp(), providers: providers) ); }
在将counter添加进providers的过程当中进行了一次包装。咱们刚才经过分析源码知道了这个操做可以让咱们处理流式数据。
经过 Provide.stream<T>(context) 就能获取数据流。须要注意的是,这里每次获取的数据流都
StreamBuilder<Counter>( initialData: currentCounter, stream: Provide.stream<Counter>(context) .where((counter) => counter.value % 2 == 0), builder: (context, snapshot) => Text('Last even value: ${snapshot.data.value}')),
不过在个人使用当中出现了streamTransformer失效的状况。在firstScreen和secondScreen一样应用这一段相同的代码,second screen的where方法可以生效,过滤掉奇数数据,而first screen中则是收到了完整的数据。
须要注意的是,这里每次获取的数据流都会从新建立一条新的流。
/// Creates a provider that listens to a stream and caches the last /// received value of the stream. /// This provider notifies for rebuild after every release. factory Provider.stream(Stream<T> stream, {T initialValue}) => _StreamProvider<T>(stream, initialValue: initialValue);
关于这个作法还有一些争议,具体能够查看这个issue:
https://github.com/google/flutter-provide/issues/3
不过这个功能还能够结合rxdart使用,能够经过stream轻松构建Observer,让咱们更加灵活的组织数据。
当咱们一个视图可能依赖于多个状态进行重建的时候,可使用ProvideMulti小部件。
自从上次写完状态管理拓展篇Rxdart以后断更了三个月。总结篇迟迟没有出来,在这里先说一声抱歉。对于我来说状态管理这个自己就是一个新鲜玩意,因此在没有通过大型应用实战检验的总结都是空谈。 这也是为何我迟迟没有开始写总结篇的缘由。不过在这我能够说一些本身的感觉,供你们参考。
在这几个月中,我用的比较多的是BLoC,它组织数据确实很是灵活,能够很轻松的实现懒加载之类的操做。并且stateful widget写的是愈来愈少了。缺点就是入门的门槛比较高,理解StreamTransformer和为何须要pipe花了我很多时间。使用bloc思惟方式须要比较大的改变,我看到了许多人在项目中使用bloc,可是用得很奇怪,还在以以前的思惟模式思考。并且bloc只是对数据进行组织,共享状态平时仍是使用的InheritWidget,确实要作不少额外的功夫。
其次我比较喜欢的就是scoped_model,理由就是简单好用。学习成本很低,并且没有写什么模版代码。
我最不想使用的状态管理方式就是redux了,一个是入门难度比较高,并且对于异步数据处理我也以为是至关麻烦的。可是闲鱼团队却是喜欢redux,以后还会开源闲鱼的状态管理框架fish_redux。因此说,可能仍是我编写的应用还不够复杂,才会有这种感觉。redux在复杂应用上可以更加清楚的划分职责,而且单向数据流以及state是immutable的特色这些都是redux的好处。
最后我再谈谈Provide。Provide总体上给个人体验很是接近Scoped,简单易上手,而且更增强大。model不用再继承,只用实现Listenable让它再也不具备侵入性。于此同时又增长了stream的特性,和bloc的作法又有几分类似。若是你使用过Scoped_model你会很快就上手。
不过能够说的是,Provide是一个很是优秀的状态管理方式,值得你去使用。可是目前该package还存在一些问题,例如Provide.stream,在将来可能会进行较大的变更,须要慎重使用。
本次代码已上传Github: https://github.com/OpenFlutter/Flutter-Notebook/tree/master/mecury_project/example/flutter_provide
若是您对Provide还有任何疑问或者文章的建议,欢迎在下方评论区以及个人邮箱1652219550a@gmail.com与我联系,我会及时回复!