Flutter里的状态机制
最近开始写flutter了, 觉得flutter里的状态同步机制还是挺有意思的,总结一下。
这里是比较好的讲解文章,基于它做一些源码分析了解下原理。
前提: 已经知道应该咋用,也知道InheritedWidget
是啥了。
Listenable
abstract class AnimatedWidget extends StatefulWidget {
const AnimatedWidget({
Key key,
@required this.listenable,
}) : assert(listenable != null),
super(key: key);
final Listenable listenable;
@protected
Widget build(BuildContext context);
/// Subclasses typically do not override this method.
@override
_AnimatedState createState() => _AnimatedState();
}
class _AnimatedState extends State<AnimatedWidget> {
@override
void initState() {
super.initState();
widget.listenable.addListener(_handleChange);
}
@override
void didUpdateWidget(AnimatedWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.listenable != oldWidget.listenable) {
oldWidget.listenable.removeListener(_handleChange);
widget.listenable.addListener(_handleChange);
}
}
@override
void dispose() {
widget.listenable.removeListener(_handleChange);
super.dispose();
}
void _handleChange() {
setState(() {
// The listenable's state is our build state, and it changed already.
});
}
@override
Widget build(BuildContext context) => widget.build(context);
}
我们看到使用listenable
的组件,会将自己注册到listener
中去,当收到监听时调用_handleChange() => setState
方法调用自己的build方法
。不需要使用方自己再调用setState
,也可以看到这里的作用域。
ScopedModel
[图片上传失败...(image-876db0-1585971080030)]
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);
}
包含数据模型,通过继承InheritedWidget
实现在父widget不需要一层层将model传给子widget
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++;
_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!
_listeners.toList().forEach((VoidCallback listener) => listener());
});
}
}
Model
继承前面说到的Listenable
,当主动调用notifyListeners
时,listeners
会收到通知
那么listeners
是什么呢?
在widget
外包了一层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) {
return AnimatedBuilder(
animation: model,
builder: (context, _) => _InheritedModel<T>(model: model, child: child),
);
}
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;
}
return AnimatedBuilder(animation: model,
builder: (context, _) => _InheritedModel<T>(model: model, child: child),
);
关键代码:
这里和InheritedWidget
不一样,就不需要setState了,notify时AnimatedBuilder
的build
函数会重新执行
class ScopedModelDescendant<T extends Model> extends StatelessWidget {
/// Called whenever the [Model] changes.
final ScopedModelDescendantBuilder<T> builder;
/// An optional constant child that does not depend on the model. This will
/// be passed as the child of [builder].
final Widget child;
/// An optional constant that determines whether the
final bool rebuildOnChange;
/// Constructor.
ScopedModelDescendant({
@required this.builder,
this.child,
this.rebuildOnChange = true,
});
@override
Widget build(BuildContext context) {
return builder(
context,
child,
ScopedModel.of<T>(context, rebuildOnChange: rebuildOnChange),
);
}
}
这里提供了ScopedModelDescendant
将model
通过ScopedModel.of
获取好给你,如果不想用这个自己通过ScopedModel.of
也没啥问题。
更新范围
ScopeModel
下的child
如果没有使用ScopedModel.of
会build
吗?, 会, 因为完全setState
了,只是不会调用didChangeDependencies
而已。可以看这里的解释,毕竟scopeModel
其实就是InheritedWidget&setState
的组合,多了一个model
层而已,而且model
还必须继承它的model
,侵入性较强
网上也有ScopeModel
的推荐用法
[图片上传失败...(image-80b027-1585971080030)]
[图片上传失败...(image-b9a12f-1585971080030)]
redux
和前端的redux
差不多,
为什么要使用redux,讲的很好,尤其是那几张动画,灰常好。
[图片上传失败...(image-56911a-1585971080030)]
- 使用了异步编程的思想,
view
被包装成StreamBuilder
, 监听stream
,store
接受到action
生成新的state
后更新stream
- 这里增加了
converter
,将store => viewmodel
,widget
可以选择监听自己需要的数据部分,避免不必要的build
class Store<State> {
/// The [Reducer] for your Store. Allows you to get the current reducer or
/// replace it with a new one if need be.
Reducer<State> reducer;
final StreamController<State> _changeController;
State _state;
List<NextDispatcher> _dispatchers;
ReducerCallback<State> _reducerCallback;
Store(
this.reducer, {
State initialState,
List<Middleware<State>> middleware = const [],
bool syncStream: false,
bool distinct: false,
})
: _changeController = new StreamController.broadcast(sync: syncStream) {
_state = initialState;
_dispatchers = _createDispatchers(
middleware,
_createReduceAndNotify(distinct),
);
}
/// Returns the current state of the app
State get state => _state;
NextDispatcher _createReduceAndNotify(bool distinct) {
return (dynamic action) {
final state = reducer(_state, action);
if (distinct && state == _state) return;
_state = state;
_changeController.add(state);
if (_reducerCallback != null) {
_reducerCallback(state, action);
}
};
}
void _setReducerCallback(ReducerCallback callback) {
_reducerCallback = callback;
}
List<NextDispatcher> _createDispatchers(
List<Middleware<State>> middleware,
NextDispatcher reduceAndNotify,
) {
final dispatchers = <NextDispatcher>[]..add(reduceAndNotify);
// Convert each [Middleware] into a [NextDispatcher]
for (var nextMiddleware in middleware.reversed) {
final next = dispatchers.last;
dispatchers.add(
(dynamic action) => nextMiddleware(this, action, next),
);
}
return dispatchers.reversed.toList();
}
void dispatch(dynamic action) {
_dispatchers[0](action);
}
Future teardown() async {
_state = null;
return _changeController.close();
}
}
通过converter
过滤stream
,以免不必要的刷新,(改进了ScopeModel
,不用setState
导致全部子节点刷新
Stream<S> _stream = widget.store.onChange;
if (widget.ignoreChange != null) {
_stream = _stream.where((state) => !widget.ignoreChange(state));
}
stream = _stream.map((_) => widget.converter(widget.store));
provider
[图片上传失败...(image-33e89f-1585971080030)]
provider
会将widget
代理给delegate
@override
Widget build(BuildContext context) {
final delegate = this.delegate as _ListenableDelegateMixin<T>;
return InheritedProvider<T>(
value: delegate.value,
updateShouldNotify: delegate.updateShouldNotify,
child: child,
);
}
mixin _ListenableDelegateMixin<T extends Listenable> on ValueStateDelegate<T> {
UpdateShouldNotify<T> updateShouldNotify;
VoidCallback _removeListener;
@override
void initDelegate() {
super.initDelegate();
if (value != null) startListening(value);
}
@override
void didUpdateDelegate(StateDelegate old) {
super.didUpdateDelegate(old);
final delegate = old as _ListenableDelegateMixin<T>;
_removeListener = delegate._removeListener;
updateShouldNotify = delegate.updateShouldNotify;
}
void startListening(T listenable, {bool rebuild = false}) {
var buildCount = 0;
final setState = this.setState;
final listener = () => setState(() => buildCount++);
var capturedBuildCount = buildCount;
if (rebuild) capturedBuildCount--;
updateShouldNotify = (_, __) {
final res = buildCount != capturedBuildCount;
capturedBuildCount = buildCount;
return res;
};
listenable.addListener(listener);
_removeListener = () {
listenable.removeListener(listener);
_removeListener = null;
updateShouldNotify = null;
};
}
@override
void dispose() {
_removeListener?.call();
super.dispose();
}
}
所以其实很好理解,在child
外包了一层ListenerProvider
,传入一个listener
组件初始化时开始监听这个listener
,当notiify
时监听函数收到回调,setState
即可进行刷新。
但最底层其实也是InheritedWidget
的作用
selector
希望provider
实现redux-converter
的能力,即只监听model
的部分属性:
@override
Widget build(BuildContext context) {
final selected = widget.selector(context);
if (oldWidget != widget || selected != value) {
value = selected;
oldWidget = widget;
cache = widget.builder(
context,
selected,
widget.child,
);
}
return cache;
}
很简单,刷新的时候用Function selector
判断下值是否有变化, 使用cache
反抗inheritedWidget
d的重复build
异步化
与streamController
结合, 只是将listenable
改成了stream
@override
Widget build(BuildContext context) {
return StreamBuilder<T>(
stream: delegate.value,
initialData: initialData,
builder: (_, snapshot) {
return InheritedProvider<T>(
value: _snapshotToValue(snapshot, context, catchError, this),
child: child,
updateShouldNotify: updateShouldNotify,
);
},
);
}
bloc-业务逻辑组件 (Business Logic Component)
总的来说,通过异步事件流 + StreamBuilder
分离UI与逻辑,同时减少build
范围。
Widget
即UI只需要关心自己需要的事件,同时发出自己的行为。
强制重建的setState()
几乎从未使用过
[图片上传失败...(image-62ef02-1585971080030)]
其实和redux
挺像的,少了action
绕一圈罢了。
下篇结合mvvm
对比下各个机制