Fish-Redux 研究
由于目前的项目采用bloc方式构建,对于的复杂页面的交互处理起来代码量越来越庞大,比如带抽屉效果的地图页面,涉及到20多个bloc之间的状态传值,而bloc的很多state的转换都依赖于widget构建,对于日益庞大的widget tree,嵌套式的bloc相互订阅,不管是从新功能开发和bug的修复都非常的不方便, 从github相关评论和用户使用量来看,Fish-Redux的设计原则和UI数据逻辑分治的核心思想,应该比较适合目前项目中的一些复杂场景,于是决定深入研究一下.原文https://github.com/alibaba/fish-redux
流程图
基本事件流
主要类关系图
工程目录如下
├── redux
│ ├── apply_middleware.dart
│ ├── basic.dart
│ ├── combine_reducers.dart
│ ├── connector.dart
│ ├── create_store.dart
│ └── redux.dart
├── redux_adapter
│ ├── adapter.dart
│ ├── dynamic_flow_adapter.dart
│ ├── recycle_context.dart
│ ├── redux_adapter.dart
│ ├── source_flow_adapter.dart
│ └── static_flow_adapter.dart
├── redux_aop
│ ├── aop.dart
│ ├── common_aop
│ └── redux_aop.dart
├── redux_component
│ ├── auto_dispose.dart
│ ├── basic.dart
│ ├── batch_store.dart
│ ├── component.dart
│ ├── context.dart
│ ├── dependencies.dart
│ ├── dependent.dart
│ ├── dispatch_bus.dart
│ ├── enhancer.dart
│ ├── helper.dart
│ ├── lifecycle.dart
│ ├── local.dart
│ ├── logic.dart
│ ├── page.dart
│ └── redux_component.dart
├── redux_component_mixin
│ ├── keep_alive_mixin.dart
│ ├── private_reducer_mixin.dart
│ ├── redux_component_mixin.dart
│ ├── single_ticker_provider_mixin.dart
│ ├── ticker_provider_mixin.dart
│ ├── visible_change_mixin.dart
│ └── widgets_binding_observer_mixin.dart
├── redux_connector
│ ├── connector.dart
│ ├── generator.dart
│ ├── map_like.dart
│ ├── none.dart
│ ├── op_mixin.dart
│ ├── redux_connector.dart
│ └── reselect.dart
├── redux_middleware
│ ├── adapter_middleware
│ ├── middleware
│ ├── redux_middleware.dart
│ └── view_middleware
├── redux_routes
│ ├── page_routes.dart
│ └── redux_routes.dart
└── utils
├── collections.dart
├── debug.dart
├── hash.dart
├── tuple.dart
└── utils.dart
在项目创建之初试了下demo,对比bloc状态和概念较多,综合考虑项目的各种因数采用了bloc,如果要将其应用到项目复杂的场景,目前还需要再细细评味下源码.
Redux->basic.dart
此类包含了fish-redux
最基本的概念,和基础类
Action: 行为事件,通常由UI界面或者某些后台服务发出,通常也称为意图, 通常在传递Action时会互带parameters作为当前传递的数据,类似Bloc中定义的
Event
class Action { const Action(this.type, {this.payload});
final Object type;
final dynamic payload;
}Reducer
: 定义了怎样修改传入的数据,它的定义如下,有两个参数,本次传入的 Action
和当前的State
,它会返回一个新的State
, 其实现逻辑有点类似Bloc
中的mapEventToState
方法(此方法在Bloc内部实现,所以在内部也能直接获取到Bloc)`Reducer<T> = T Function(T state, Action action);`
Dispatch: 定义了怎么放松一个
Action
意图typedef Dispatch = dynamic Function(Action action);
基于Redux衍生出的一些其它的概念
Connector
: 两个Object之间的连接的桥梁,其实就是定义了一个State怎么转换成为另外一个State类型,类比Bloc中的实现,Bloc中主要是通过Event传递数据再进行转换,此处相当于mapEventToState
进一步细化abstract class AbstractConnector<S, P> { P get(S state);
SubReducer<S> subReducer(Reducer<P> reducer);
}SubReducer
: 一个函数用于修改部分data的函数, 对比 Reducer
可以看出它多一个参数isStateCopied
,用于性能优化typedef SubReducer<T> = T Function(T state, Action action, bool isStateCopied);
其它概念-事件订阅
Subscribe: 输入订阅并可以通过Result结束订阅,功能类似
StreamSubscription
和listen
的组合typedef Subscribe = void Function() Function(void Function() callback);
Store: 数据存储,用于存储
State
typedef StoreCreator<T> = Store<T> Function( T preloadedState,
Reducer<T> reducer,
);- 从它的定义来看,它存储了Redux交互过程层中的关键对象,持有当前Redux上下文信息,姑且可以把它理解为Bloc实力本身吧.
dart class Store<T> {
小结: redux/basic.dart主要定义了basic的概念,和一些轻量级的函数
Get<T> getState;
Dispatch dispatch;
Subscribe subscribe;
Observable<T> observable;
ReplaceReducer<T> replaceReducer;
Future<dynamic> Function() teardown;
}
- 从它的定义来看,它存储了Redux交互过程层中的关键对象,持有当前Redux上下文信息,姑且可以把它理解为Bloc实力本身吧.
中间件
- Middleware: 中间件,返回一个可以合成的Dispatch
```dart
typedef Middleware
Dispatch dispatch,
Get
});
typedef StoreCreator
T preloadedState,
Reducer
);
typedef StoreEnhancer
```
Redux->apply_middleware.dart
- 插入中间,主要作用于
Dispatch
过程dart StoreEnhancer<T> applyMiddleware<T>(List<Middleware<T>> middleware) {
Redux->combine_reducers.dart
此类主要负责redux的action和state事件的合并处理,以及Reducer的转换
- combineSubReducers
- combineReducers
- castReducer
Redux->connector.dart
- state转换
abstract class ImmutableConn<T, P> implements AbstractConnector<T, P> { ...
abstract class MutableConn<T, P> implements AbstractConnector<T, P> { ...
Redux->create_store.dart
- 创建Store
Store<T> _createStore<T>(final T preloadedState, final Reducer<T> reducer) {
/// 1. 初始化 `preloadedState`必须为非空状态,Store至少要有一个State
/// 2. 创建一个`List<_VoidCallback> _listeners`,用于保存监听者 (subscribe1)
/// 3. 用于同步传递一个State的流,这样其他组件可以通过Stream订阅当前Store的State是否变更
final StreamController<T> _notifyController =
StreamController<T>.broadcast(sync: true);
/// 4. 事件Action的派发过程监控,action执行完毕才能之后后一个
try {
_isDispatching = true;
_state = _reducer(_state, action);
} finally {
_isDispatching = false;
}
/// 5. 订阅是事件回调用 (subscribe2)
for (_VoidCallback listener in _notifyListeners) {
listener();
}
/// 6. 可选择性的替换Reduer,更加灵活,相当Bloc对于于同一个Event每次map时执行的方法不一样,默认不做处理
..replaceReducer = (Reducer<T> replaceReducer) {
_reducer = replaceReducer ?? _noop;
}
/// 7. 添加订阅者,所以subscribe的返回值执行能移除订阅者,这样通过`Subscribe`可以为Store添加多个订阅者 (subscribe3),
..subscribe = (_VoidCallback listener) { ...
_listeners.add(listener); ...
return () { ...
_listeners.remove(listener);
};
/// 8. 添加Observer事件流的订阅,和subscribe功能大致相同,没有太多的断言限制
..observable = (() => _notifyController.stream)
/// 9. 销毁Store的订阅者
..teardown = () {
_isDisposed = true;
_listeners.clear();
return _notifyController.close();
};
- 创建增强版的Store,主要是为了应用中间件
Store<T> createStore<T>(T preloadedState, Reducer<T> reducer,
[StoreEnhancer<T> enhancer]) =>
enhancer != null
? enhancer(_createStore)(preloadedState, reducer)
: _createStore(preloadedState, reducer);
redux_component->basic.dart
- ViewBuilder: 返回一个Widget,用于提供渲染户界面的的配置信息,
Dispatch
则是用于发送事件,该事件会经过reducer,在Reducer进行相应的逻辑处理
typedef ViewBuilder<T> = Widget Function(
T state,
Dispatch dispatch,
ViewService viewService,
);
- ListBuildAdapter: 主要用户配置
ListView.builder
,改善页面滑动性能
class ListAdapter {
final int itemCount;
final IndexedWidgetBuilder itemBuilder;
const ListAdapter(this.itemBuilder, this.itemCount);
}
- AdapterBuilder: 配置
ListAdapter
一起使用
typedef AdapterBuilder<T> = ListAdapter Function(
T state,
Dispatch dispatch,
ViewService viewService,
);
- ViewUpdater: 驱动UI的数据源,决定视图的创建和更新时机
abstract class ViewUpdater<T> {
Widget buildWidget();
void didUpdateWidget();
void onNotify();
void forceUpdate();
void clearCache();
}
- ShouldUpdate: 控制component刷新
typedef ShouldUpdate<T> = bool Function(T old, T now);
- ExtraData: 除了State之外,在上下文中配置一些全局的信息
abstract class ExtraData {
/// Get|Set extra data in context if needed.
Map<String, Object> get extra;
}
///1. ViewService: 提供Component
abstract class ViewService implements ExtraData { ...
ListAdapter buildAdapter();
///配置其他组件,动态获取
Widget buildComponent(String name, {Widget defaultWidget});
/// ViewService的寄居的Widget所对应的Context
BuildContext get context;
/// 发送action事件给其他的接受者
void broadcast(Action action);
}
///2. Context
abstract class Context<T> extends AutoDispose implements ExtraData {
/// Get the latest state
T get state;
/// The way to send action, which will be consumed by self, or by broadcast-module and store.
dynamic dispatch(Action action);
/// Get BuildContext from the host-widget
BuildContext get context;
/// 用来传递 `Component`组件 `mixin`属性,如tickerProvider
State get stfState;
Widget buildComponent(String name);
void broadcast(Action action);
void broadcastEffect(Action action, {bool excluded});
void Function() addObservable(Subscribe observable);
void forceUpdate();
void Function() listen({
bool Function(T, T) isChanged,
void Function() onChange,
});
}
- ContextSys: 提供系统相关的上下文信息
abstract class ContextSys<T> extends Context<T> implements ViewService {
void onLifecycle(Action action); //相应系统的lifeCycle事件
void bindForceUpdate(void Function() forceUpdate);
Store<dynamic> get store;
Enhancer<dynamic> get enhancer;
DispatchBus get bus;
}
- Dependent
abstract class Dependent<T> {
Get<Object> subGetter(Get<T> getter);
SubReducer<T> createSubReducer();
Widget buildComponent(
Store<Object> store,
Get<T> getter, {
@required DispatchBus bus,
@required Enhancer<Object> enhancer,
});
/// P state
ListAdapter buildAdapter(ContextSys<Object> ctx);
ContextSys<Object> createContext(
Store<Object> store,
BuildContext buildContext,
Get<T> getState, {
@required DispatchBus bus,
@required Enhancer<Object> enhancer,
});
bool isComponent();
bool isAdapter();
}
- Dependent: 依赖的抽象程,根据此类的定义主要有两种依赖,一种是适配器依赖,用于对List进行适配的依赖,另外一种是用于构建新的Component
abstract class Dependent<T> {
Get<Object> subGetter(Get<T> getter);
SubReducer<T> createSubReducer();
Widget buildComponent(
Store<Object> store,
Get<T> getter, {
@required DispatchBus bus,
@required Enhancer<Object> enhancer,
});
/// P state
ListAdapter buildAdapter(ContextSys<Object> ctx);
ContextSys<Object> createContext(
Store<Object> store,
BuildContext buildContext,
Get<T> getState, {
@required DispatchBus bus,
@required Enhancer<Object> enhancer,
});
bool isComponent();
bool isAdapter();
}
- AbstractLogic: 名字代表它的功能,封装component的逻辑,主要包括两类逻辑` Reducer & SideEffect.
abstract class AbstractLogic<T> {
Reducer<T> get reducer;
/// State适配
Object onReducer(Object state, Action action);
/// Dispatch事件适配
Dispatch createEffectDispatch(ContextSys<T> ctx, Enhancer<Object> enhancer);
Dispatch createNextDispatch(ContextSys<T> ctx, Enhancer<Object> enhancer);
Dispatch createDispatch(
Dispatch effectDispatch,
Dispatch nextDispatch,
ContextSys<T> ctx,
);
/// 系统上下文
ContextSys<T> createContext(
Store<Object> store,
BuildContext buildContext,
Get<T> getState, {
@required DispatchBus bus,
@required Enhancer<Object> enhancer,
});
/// 为当前的逻辑对象设定key,用于复用
Object key(T state);
/// 从slot找查找对应的依赖
Dependent<T> slot(String name);
/// 获取一个适配器依赖 adapter Dependent
Dependent<T> adapterDep();
Type get propertyType;
}
/// 基于Component的抽象逻辑协议,`AbstractComponent`定义了它的用户视图窗口的配置信息
abstract class AbstractComponent<T> implements AbstractLogic<T> {
Widget buildComponent(
Store<Object> store,
Get<T> getter, {
@required DispatchBus bus,
@required Enhancer<Object> enhancer,
});
}
redux_component->auto_dispose.dart
AutoDispose: 自动释放,根据咸鱼的文档描述,它是一个轻量级的生命周期管理对象
- 当这个继承于AutoDispose的对象被释放时,释放它的所有Child,断开和Parent之间的联系,触发OnDispose的回调事件
通过
_Fields
和Parent
和Child
进行关联class _Fields { bool isDisposed = false;
Set<AutoDispose> children;
AutoDispose parent;
void Function() onDisposed;
}通过
visit
来实现对上下游想关联的对象遍历操作,和flutter framework中的widget更新时采用visit方式类似,通过visit
和visitor
方法,利用多态的特性,接耦操作dispose:
void dispose() { ... for (AutoDispose child in copy) { ...
child.dispose();
_fields.parent?._fields?.children?.remove(this); ...
_fields.onDisposed?.call(); ...
_fields.isDisposed = true;
}- onDisposed
void onDisposed(void Function() onDisposed) { assert(_fields.onDisposed == null);
if (_fields.isDisposed) {
onDisposed?.call();
} else {
_fields.onDisposed = onDisposed;
}
}
AutoDispose registerOnDisposed(void Function() onDisposed)
redux_component->batch_store.dart
- 在
Store
的基础上再次进行封装,对Store的订阅事件进行默认的批处理绑定 - 监听来自engine每一帧绘制完成的回调,批量的传递给store的每个订阅者
class _BatchStore<T> extends Store<T> with _BatchNotify<T> {
_BatchStore(Store<T> store) : assert(store != null) {
getState = store.getState;
subscribe = store.subscribe;
replaceReducer = store.replaceReducer;
dispatch = store.dispatch;
observable = store.observable;
teardown = store.teardown;
//初始化的时候绑定所有listen的人订阅事件
setupBatch();
}
}
mixin _BatchNotify<T> on Store<T> {
final List<void Function()> _listeners = <void Function()>[];
bool _isBatching = false;
bool _isSetupBatch = false;
T _prevState;
void setupBatch() { ...
///1. 外部的所有订阅事件通过`_batch`方法进行默认绑定
super.subscribe(_batch);
subscribe = (void Function() callback) { ...
_listeners.add(callback);
return () {
_listeners.remove(callback);
};
};
}
}
/// 界面更新时间回调注册,条件过滤,
bool isInSuitablePhase() {
return SchedulerBinding.instance != null &&
SchedulerBinding.instance.schedulerPhase !=
SchedulerPhase.persistentCallbacks &&
!(SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle &&
WidgetsBinding.instance.renderViewElement == null);
}
/// 2. 批处理页面的刷新事件回调
void _batch() {
if (!isInSuitablePhase()) {
if (!_isBatching) {
_isBatching = true;
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
if (_isBatching) {
_batch(); ...
} else {
final T curState = getState();
if (!identical(_prevState, curState)) { ...
for (void Function() listener in notifyListeners) {
listener();
}
_isBatching = false;
连接连个Store,代码上看主要是一个Store订阅了另外一个Store的State
Store<T> connectStores<T, K>( Store<T> mainStore,
Store<K> extraStore,
T Function(T, K) update,
) {
/// 1. 注册state的更新事件
final void Function() subscriber = () {
final T prevT = mainStore.getState();
final T nextT = update(prevT, extraStore.getState());
if (nextT != null && !identical(prevT, nextT)) {
mainStore.dispatch(Action(_UpdateState.Assign, payload: nextT));
}
};
/// 2. 绑定另外一个store的state变更事件,因为state变更时,会通知它的listener
final void Function() unsubscribe = extraStore.subscribe(subscriber);
///3. 订阅另外一个store,接收地一个state
subscriber();
///4. 取消另一个store的订阅并释放当前的store资源
final Future<dynamic> Function() superMainTD = mainStore.teardown;
mainStore.teardown = () {
unsubscribe?.call();
return superMainTD();
};
return mainStore;
}
redux_component->component.dart
- 定义了页面构成的基本元素,也是用户界面的入口
通过Component来提供一个widget,基于Component和它的widget创建以及销毁,可以分为:
initState, didChangeDependencies,
build,
reassemble,
didUpdateWidget,
deactivate,
dispose,基于ListView循环复用的小部件Widget,如
Cell,Card,ListItem
又增加了2个状态appear
和disappear
Component它作为一个Widget的提供者,通过lifeCycle触发了系列的事件绑定,通过
logic
的层层抽象,将不同的逻辑分散到不同的抽象层中,处理不同的业务逻辑,以Commpnent为中心
Tips
- 订阅事件多采用了
Function() action(Function listener)
加内置listeners
数组,来实现订阅和解除订阅的操作。
void Function() registerReceiver(Dispatch dispatch) {
assert(!_dispatchList.contains(dispatch),
'Do not register a dispatch which is already existed');
if (dispatch != null) {
_dispatchList.add(dispatch);
return () {
_dispatchList.remove(dispatch);
};
} else {
return null;
}
}
- context中的widget缓存
class ComponentState<T> extends State<ComponentWidget<T>> { ...
Widget buildWidget() {
Widget result = _widgetCache;
if (result == null) {
result = _widgetCache = view(state, dispatch, this);
dispatch(LifecycleCreator.build(name));
}
return result;
}
在
helper.dart
对Reduce
和Enhancer系列因子
进行了大量的reduce
,merge
,combine
操作,在框架内部自动的对分散的逻辑进行集中管理
在widget之间的关系处理上利用
Dependencies
和Dependent
进行连接,通过Connector
来传递不同state的数据. 如下是一次基本的执行过程