Flutter的不少灵感来自于React,它的设计思想是数据与视图分离,由数据映射渲染视图。因此在Flutter中,它的Widget是immutable的,而它的动态部分所有放到了状态(State)中。react
假如你曾进行过react开发,也许你一下会想到Redux。flutter有相似redux的状态管理的库吗?答案是确定的,可是有关在flutter中使用redux的应用实践咱们会在以后的文章中进行介绍。git
这个系列将会从这几个状态管理方案进行深刻研究:github
今天要和你们分享的是第一篇,使用Scoped_model进行状态管理。redux
在咱们一开始构建应用的时候,也许很简单。咱们有一些状态,直接把他们映射成视图就能够了。这种简单应用可能并不须要状态管理。架构
可是随着功能的增长,你的应用程序将会有几十个甚至上百个状态。这个时候你的应用应该会是这样。app
这时候,咱们便迫切的须要一个架构来帮助咱们理清这些关系,状态管理框架应运而生。框架
Scoped_model是一个dart第三方库,提供了让您可以轻松地将数据模型从父Widget传递到它的后代的功能。此外,它还会在模型更新时从新渲染使用该模型的全部子项。less
它直接来自于Google正在开发的新系统Fuchsia核心Widgets 中对Model类的简单提取,做为独立使用的独立Flutter插件发布。ide
Scoped model使用了观察者模式,将数据模型放在父代,后代经过找到父代的model进行数据渲染,最后数据改变时将数据传回,父代再通知全部用到了该model的子代去更新状态。post
而咱们则须要将它们放在顶层入口MaterialApp之上,这样就能进行全局的状态管理了。
这里咱们以一个最简单的CountApp举例,详细介绍Scoped_model的用法。该项目完整代码已放在github仓库。
这是一个在不一样页面使用Scoped共享状态信息的app。这两个页面都依赖于一个数字,这个数字会随着咱们按下按钮的次数而增长。
在pubspec中添加scoped_model的依赖。
在Scoped中,Model是一个只包含与状态相关信息的单位。咱们应该把状态数据与操做数据的方法抽象出来封装到Model中。
import 'package:scoped_model/scoped_model.dart';
class CountModel extends Model{
int _count = 0;
get count => _count;
void increment(){
_count++;
notifyListeners();
}
}
复制代码
//建立顶层状态
CountModel countModel = CountModel();
@override
Widget build(BuildContext context) {
return ScopedModel<CountModel>(
model: countModel,
child: new MaterialApp(
home: TopScreen(),
),
);
}
复制代码
咱们能够从前面的演示图片中看出,一共有两个页面,都使用了同一个model。 Scoped_model提供了两种方式在子页面中获取model。咱们先来介绍第一种,使用ScopedModelDescendant获取model。
@override
Widget build(BuildContext context) {
return ScopedModelDescendant<CountModel>(
builder: (context,child,model){
return Scaffold(
body: Center(
child: Text(
model.count.toString(),
style: TextStyle(fontSize: 48.0),
),
),
);
},
);
}
复制代码
floatingActionButton: new FloatingActionButton(
onPressed: () => model.increment(),
tooltip: 'Increment',
child: new Icon(Icons.add),
)
复制代码
第二种获取model的方式——使用ScopedModel.of
final countModel = ScopedModel.of<CountModel>(context);
countModel.increment();
复制代码
或者在Model中重写of方法
class CountModel extends Model{
int _count = 0;
get count => _count;
void increment(){
_count++;
notifyListeners();
}
//重写of方法
CountModel of(context) =>
ScopedModel.of<CountModel>(context);
}
复制代码
而后直接经过CountModel获取model实例
final countModel2 = CountModel().of(context);
复制代码
这种方式彷佛让咱们的代码有更好的可阅读性。
【注意:】咱们在使用第二种方式的时候,rebuildOnChange属性默认为false,因此会致使没法刷新(同步)状态的状况发生,须要手动指定rebuildOnChange:true。这里要很是感谢@荣毅coolboy同窗的分享!
要解决这个问题很简单,使用Mixin!
class MainModel extends Model with AModel,BModel,CModel{}
复制代码
而后将MainModel放在顶层便可。 这里有一个比较完整的使用ScopedModel管理状态的应用,详细用法可参考该项目。
在不一样页面间的数据传递使用了InheritedWidget。
因为Model必须继承至Model类,因此它就具备了侵入性。之后假如不用scoped进行状态管理那么必然会带来须要更改多处代码的状况。这并非咱们但愿看到的结果。
在flutter中,Scoped_model是一种很是简单易上手,并能保持代码高可阅读性的一种新的状态管理方式,值得各位去尝试一下!
本次所用到的代码已经上传Github: github.com/Vadaski/Vad…
若是您对scoped还有任何疑问或者文章的建议,欢迎在下方评论区以及个人邮箱1652219550a@gmail.com与我联系,我会及时回复!
下一章咱们将探索Redux在Flutter中的实践,敬请关注。