scoped_model
scoped_model 是Flutter 中最簡單的狀態框架 ,他主要使用了InheritedWidget 來共享狀態,Microtask(微隊列)來做的異步, 寫的可以說是非常的小而精
想要看懂scoped_model 我們先來復習一下使用 InheritedWidget 的流程, 我們簡單的將共享數據的widget 命名為Provider
,消費者命名為Consumer ,方便我們接下來的理解
創建數據模型 model 繼承自 Listenable ,這個就是共享的數據 重寫他的 addListener removeListener 和 notifyListeners()
我們平時可以使用 ChangeNotifier ,他實現了帶有 callback 的 addListener removeListener 和 notifyListeners()創建一個數據的提供者 Provider ,他包含需要共享的數據 data,并會在被加載和移除時添加和刪除監聽,所以他是一個StatefulWidget,我們需要重寫他的initState() dispose() 和 didUpdateWidget() 這三個方法,同時他還含有一個InheritedWidget 作為child,來為他提供一個向下傳遞數據的能力,
3.Provider 是提供了一個向下共享數據的能力, 我還需要一個查找著,他擁有著可以關聯子widget和 Provider 的關系(并非強制 ,提供是否關聯參數),我們這里寫一下通用的寫法
static T of<T extends ChangeNotifier>(BuildContext buildContext,{bool rebuild=true}){
if(rebuild){
return buildContext.dependOnInheritedWidgetOfExactType<InheritedProvider<T>>().data;
}
var p= buildContext.getElementForInheritedWidgetOfExactType<InheritedProvider<T>>().widget as InheritedProvider<T>;
return p.data;
}
buildContext.getElementForInheritedWidgetOfExactType 看到了這個方法有沒有想起來在Element 那篇文章中,我們提到過的InheritedWidget 是如何共享數據的,沒錯 Widget 是通過 持有element 在 element 的 mount 的方法中 加載父widget 的 InheritedWidget , 所以這個方法名是以 ElementFor 開頭的
4.數據的持有者 提供者都有了,其實在這里我們利用 上面3 的靜態方法其實在子widget中就可以獲取到數據了,但是如果們繼續封裝接受者的話,可以方便使用者調用 ,使用者就是一個普通的StatelessWidget ,我們在他內部創建一個builder
final Widget Function(BuildContext buildContext,T data) builder; 在StatelessWidget 的build 方法直接調用builder 就可以了,省去了每次都要寫獲取數據的步驟 即 ChangeNotifyProvider.of(context,useData: true)
整個 InheritedWidget 的使用過程就已經完成了,接下來我們按照這個順序去看scoped_model 的源碼,就方便多了,每一步都會和源碼中一一對應上,我們就按照上面的步驟來分析
我會刪除部分代碼,讓大家看的更簡潔,
1.創建數據模型
abstract class Model extends Listenable {
final Set<VoidCallback> _listeners = Set<VoidCallback>();
int _version = 0;
int _microtaskVersion = 0;
@override
void addListener(VoidCallback listener) {
_listeners.add(listener);
}
@override
void removeListener(VoidCallback listener) {
_listeners.remove(listener);
}
@protected
void notifyListeners() {
...
if (_microtaskVersion == _version) {
_microtaskVersion++;
scheduleMicrotask(() {
_version++;
_microtaskVersion = _version;
_listeners.toList().forEach((VoidCallback listener) => listener());
});
}
}
}
2.創建提供者 一個StatefulWidget 包含 InheritedWidget ,
class ScopedModel<T extends Model> extends StatelessWidget {
final T model;
final Widget child;
ScopedModel({@required this.model, @required this.child})
: assert(model != null),
assert(child != null);
@override
Widget build(BuildContext context) {
return ModelBuilder<T>(
model: model,
builder: (context) => _InheritedModel<T>(model: model, child: child),
);
}
class ModelBuilder<T extends Model> extends StatefulWidget {
final T model;
final WidgetBuilder builder;
const ModelBuilder({this.model, this.builder});
@override
_ModelBuilderState createState() => new _ModelBuilderState();
}
class _ModelBuilderState extends State<ModelBuilder> {
@override
void initState() {
super.initState();
widget.model.addListener(_onChange);
}
@override
void didUpdateWidget(ModelBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.model != oldWidget.model) {
oldWidget.model.removeListener(_onChange);
widget.model.addListener(_onChange);
}
}
@override
void dispose() {
widget.model.removeListener(_onChange);
super.dispose();
}
@override
Widget build(BuildContext context) => widget.builder(context);
void _onChange() => setState(() {});
}
class _InheritedModel<T extends Model> extends InheritedWidget {
final T model;
final int version;
_InheritedModel({Key key, Widget child, T model})
: this.model = model,
this.version = model._version,
super(key: key, child: child);
@override
bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
(oldWidget.version != version);
}
這里他又使用了一個StatelessWidget 封裝了一下我們所說的步驟,方便閱讀和理解
3.創建數據查找著
class ModelFinder<T extends Model> {
T of(BuildContext context, {bool rebuildOnChange: false}) {
return ScopedModel.of<T>(context, rebuildOnChange: rebuildOnChange);
}
}
static T of<T extends Model>(
BuildContext context, {
bool rebuildOnChange = false,
}) {
final Type type = _type<_InheritedModel<T>>();
Widget widget = rebuildOnChange
? context.inheritFromWidgetOfExactType(type)
: context.ancestorWidgetOfExactType(type);
if (widget == null) {
throw new ScopedModelError();
} else {
return (widget as _InheritedModel<T>).model;
}
}
static Type _type<T>() => T;
4.創建消費者
class ScopedModelDescendant<T extends Model> extends StatelessWidget {
final ScopedModelDescendantBuilder<T> builder;
final Widget child;
final bool rebuildOnChange;
ScopedModelDescendant({
@required this.builder,
this.child,
this.rebuildOnChange = true,
});
@override
Widget build(BuildContext context) {
return builder(
context,
child,
ScopedModel.of<T>(context, rebuildOnChange: rebuildOnChange),
);
}
}
具體的使用方法和InheritedWidget 一致, 提供者包裹業務界面,子widget 直接提供數據模型獲取數據,
仔細看一下代碼,其實并沒有什么難度,希望對大家的學習有所幫助
我學習flutter的整個過程都記錄在里面了
http://www.lxweimin.com/c/36554cb4c804
最后附上demo 地址