Flutter 无状态管理相当于 Androi 的mvc模式,数据UI写在一块,写起来简单,但是逻辑代码复杂,
不利于维护,接下来我会逐一解锁Flutter的状态管理。
### Scoped Model介绍
Scoped Model 利用 model 的方式,轻松的将数据模型从父 Widget 传递到它的后代,并且此数据
模型实现观察者模式,当数据改变时,会通知实现的子类,重新构建新的子类 Widget 达到数据刷新的目的 。
/// A base class that holds some data and allows other classes to listen to
/// changes to that data.
/// In order to notify listeners that the data has changed, you must explicitly
/// call the [notifyListeners] method.
/// Generally used in conjunction with a [ScopedModel] Widget, but if you do not
/// need to pass the Widget down the tree, you can use a simple [AnimatedBuilder]
/// to listen for changes and rebuild when the model notifies the listeners.
Scoped Model 原理
Model 继承了 Listenable 抽象类,在 Model 中实现了抽象方法,Listenable中体现了注册监听,notifyListener通知子类数据已经改变。
abstract class Model extends Listenable
///注册监听
/// Register a closure to be called when the object notifies its listeners.
void addListener(VoidCallback listener);
///删除监听
/// Remove a previously registered closure from the list of closures that the
/// object notifies.
void removeListener(VoidCallback listener);
///通知监听者
@protected
void notifyListeners() {...}
源码分析
Model源码分析
abstract class Model extends Listenable {
//创建一个监听的回调集合
final Set<VoidCallback> _listeners = Set<VoidCallback>();
int _version = 0;
int _microtaskVersion = 0;
/// [listener] will be invoked when the model changes.
@override
void addListener(VoidCallback listener) {
_listeners.add(listener);
}
/// [listener] will no longer be invoked when the model changes.
@override
void removeListener(VoidCallback listener) {
_listeners.remove(listener);
}
/// Returns the number of listeners listening to this model.
int get listenerCount => _listeners.length;
/// Should be called only by [Model] when the model has changed.
@protected
void notifyListeners() {
// We schedule a microtask to debounce multiple changes that can occur
// all at once.
if (_microtaskVersion == _version) {
_microtaskVersion++;
//调用消息队列
scheduleMicrotask(() {
//_version 改变会通知子类数据已改变,在_InheritedModel 这个类中有说明
_version++;
_microtaskVersion = _version;
// Convert the Set to a List before executing each listener. This
// prevents errors that can arise if a listener removes itself during
// invocation!
//执行Callback,通知子类
_listeners.toList().forEach((VoidCallback listener) => listener());
});
}
}
}
ScopedModel 源码分析
class ScopedModel<T extends Model> extends StatelessWidget {
/// The [Model] to provide to [child] and its descendants.
final T model;
/// The [Widget] the [model] will be available to.
final Widget child;
ScopedModel({@required this.model, @required this.child})
: assert(model != null),
assert(child != null);
@override
Widget build(BuildContext context) {
///The [animation] and [builder] arguments must not be null.
/// 子类不能为空,否则在下面会抛出异常throw new ScopedModelError();
/// 构建 _InheritedModel 这样就能解释为什么子类能够从父类中获取数据了
return AnimatedBuilder(
animation: model,
builder: (context, _) => _InheritedModel<T>(model: model, child: child),
);
}
......
if (widget == null) {
/// 抛出异常
throw new ScopedModelError();
} else {
return (widget as _InheritedModel<T>).model;
}
}
}
///小结:ScopedModel会构建_InheritedModel 小部件,这样实现数据的传递
_InheritedModel 源码分析
/// _InheritedModel 继承InheritedWidget
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);
/// 当version 改变时 updata 更新
@override
bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
(oldWidget.version != version);
}
总结:在最外层创建一个model,返回一个_InheritedModel类型的widget,通过Inherited小部件向子类传递数据,同时通过观察者模式
通知所有的子类去刷新UI,达到以Model驱动UI的效果。
由于时间原因,写的没那么详细,请见谅,以后会追加使用的方法。