Mobx 可能先前H5 使用的较多,楼主为Android 原生开发转Flutter ,对Mobx较为陌生,在使用Mobx时想确认该框架如何实现局部刷新。
本文只涉及Mobx 局部刷新的实现原理,Mobx的具体使用方法,可以百度查询
Mobx会自动创建xxxx.g.dart 文件
@override
String? get currentShowCard {
_$currentShowCardAtom.reportRead();
return super.currentShowCard;
}
@override
set currentShowCard(String? value) {
_$currentShowCardAtom.reportWrite(value, super.currentShowCard, () {
super.currentShowCard = value;
});
}
可以看到,set方法调用时会使用到reporWrite方法
void reportWrite<T>(T newValue, T oldValue, void Function() setNewValue) {
context.spyReport(ObservableValueSpyEvent(this,
newValue: newValue, oldValue: oldValue, name: name));
final actionName = context.isSpyEnabled ? '${name}_set' : name;
// ignore: cascade_invocations
context.conditionallyRunInAction(() {
setNewValue();
reportChanged();
}, this, name: actionName);
// ignore: cascade_invocations
context.spyReport(EndedSpyEvent(type: 'observable', name: name));
}
context.conditionallyRunInAction(() {
setNewValue();
reportChanged();
}, this, name: actionName);
这里reportChanged()就是通知刷新的入口。
void reportChanged() {
_context
..startBatch()
..propagateChanged(this)
..endBatch();
}
..propagateChanged(this)是重点
void propagateChanged(Atom atom) {
if (atom._lowestObserverState == DerivationState.stale) {
return;
}
atom._lowestObserverState = DerivationState.stale;
for (final observer in atom._observers) {
if (observer._dependenciesState == DerivationState.upToDate) {
observer._onBecomeStale();
}
observer._dependenciesState = DerivationState.stale;
}
}
可以看到这个方法里面有个循环,轮询通知各个监听刷新状态,oberver是Derivation 抽象类的实现
abstract class Derivation {
String get name;
late Set<Atom> _observables;
Set<Atom>? _newObservables;
MobXCaughtException? _errorValue;
MobXCaughtException? get errorValue;
late DerivationState _dependenciesState;
void _onBecomeStale();
// ignore: unused_element
void _suspend();
}
我们接着跟踪源码
abstract class Reaction implements Derivation {
bool get isDisposed;
void dispose();
void _run();
}
class ReactionImpl implements Reaction {
ReactionImpl(this._context, Function() onInvalidate,
{required this.name, void Function(Object, Reaction)? onError}) {
_onInvalidate = onInvalidate;
_onError = onError;
}
...
}
可以看到ReactionImpl是具体实现类,那么具体刷新逻辑肯定也就是由它实现的
@override
void _onBecomeStale() {
schedule();
}
ReactionImpl 的 _onBecomeStale 方法很简明,继续往下看
void schedule() {
if (_isScheduled) {
return;
}
_isScheduled = true;
_context
..addPendingReaction(this)
..runReactions();
}
..runReactions() 重点在方法
void runReactions() {
if (_state.batch > 0 || _state.isRunningReactions) {
return;
}
_runReactionsInternal();
}
void _runReactionsInternal() {
_state.isRunningReactions = true;
...
final remainingReactions = allReactions.toList(growable: false);
allReactions.clear();
for (final reaction in remainingReactions) {
reaction._run();
}
}
_state
..pendingReactions = []
..isRunningReactions = false;
}
_runReactionsInternal 方法里面有个轮询调用reaction._run(); ReactionImpl 类里面有_run() 方法具体实现逻辑。
@override
void _run() {
if (_isDisposed) {
return;
}
_context.startBatch();
_isScheduled = false;
if (_context._shouldCompute(this)) {
try {
_onInvalidate();
} on Object catch (e, s) {
// Note: "on Object" accounts for both Error and Exception
_errorValue = MobXCaughtException(e, stackTrace: s);
_reportException(_errorValue!);
}
}
_context.endBatch();
}
_onInvalidate() 方法就是最终的实现方法。该方法是在ReactionImpl构造方法传入
ReactionImpl(this._context, Function() onInvalidate,
{required this.name, void Function(Object, Reaction)? onError}) {
_onInvalidate = onInvalidate;
_onError = onError;
}
mixin ObserverWidgetMixin on Widget {
/// An identifiable name that can be overriden for debugging.
String getName();
/// The context within which its reaction should be run. It is the
/// [mainContext] in most cases.
ReactiveContext getContext() => mainContext;
/// A convenience method used for testing.
@visibleForTesting
Reaction createReaction(
Function() onInvalidate, {
Function(Object, Reaction)? onError,
}) =>
ReactionImpl(
getContext(),
onInvalidate,
name: getName(),
onError: onError,
);
...
}
mixin ObserverElementMixin on ComponentElement {
ReactionImpl get reaction => _reaction;
late ReactionImpl _reaction;
// Not using the original `widget` getter as it would otherwise make the mixin
// impossible to use
ObserverWidgetMixin get _widget => widget as ObserverWidgetMixin;
@override
void mount(Element? parent, dynamic newSlot) {
_reaction = _widget.createReaction(invalidate, onError: (e, _) {
FlutterError.reportError(FlutterErrorDetails(
library: 'flutter_mobx',
exception: e,
stack: e is Error ? e.stackTrace : null,
));
}) as ReactionImpl;
super.mount(parent, newSlot);
}
void invalidate() => markNeedsBuild();
...
}
最后我们终于找到了最终节点invalidate() 方法
总上,Mobx 在变量更新后调用markNeedsBuild() 来通知Flutter 框架进行更新。