Flutter 無狀態(tài)管理相當(dāng)于 Androi 的mvc模式,數(shù)據(jù)UI寫在一塊,寫起來簡單,但是邏輯代碼復(fù)雜,
不利于維護,接下來我會逐一解鎖Flutter的狀態(tài)管理。
Scoped Model介紹
Scoped Model 利用 model 的方式,輕松的將數(shù)據(jù)模型從父 Widget 傳遞到它的后代,并且此數(shù)據(jù)
模型實現(xiàn)觀察者模式,當(dāng)數(shù)據(jù)改變時,會通知實現(xiàn)的子類,重新構(gòu)建新的子類 Widget 達到數(shù)據(jù)刷新的目的 。
/// 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 中實現(xiàn)了抽象方法,Listenable中體現(xiàn)了注冊監(jiān)聽,notifyListener通知子類數(shù)據(jù)已經(jīng)改變。
abstract class Model extends Listenable
///注冊監(jiān)聽
/// Register a closure to be called when the object notifies its listeners.
void addListener(VoidCallback listener);
///刪除監(jiān)聽
/// Remove a previously registered closure from the list of closures that the
/// object notifies.
void removeListener(VoidCallback listener);
///通知監(jiān)聽者
@protected
void notifyListeners() {...}
源碼分析
Model源碼分析
abstract class Model extends Listenable {
//創(chuàng)建一個監(jiān)聽的回調(diào)集合
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++;
//調(diào)用消息隊列
scheduleMicrotask(() {
//_version 改變會通知子類數(shù)據(jù)已改變,在_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!
//執(zhí)行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();
/// 構(gòu)建 _InheritedModel 這樣就能解釋為什么子類能夠從父類中獲取數(shù)據(jù)了
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;
}
}
}
///小結(jié):ScopedModel會構(gòu)建_InheritedModel 小部件,這樣實現(xiàn)數(shù)據(jù)的傳遞
_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);
/// 當(dāng)version 改變時 updata 更新
@override
bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
(oldWidget.version != version);
}
總結(jié):在最外層創(chuàng)建一個model,返回一個_InheritedModel類型的widget,通過Inherited小部件向子類傳遞數(shù)據(jù),同時通過觀察者模式
通知所有的子類去刷新UI,達到以Model驅(qū)動UI的效果。
由于時間原因,寫的沒那么詳細,請見諒,以后會追加使用的方法。