zoukankan      html  css  js  c++  java
  • 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结束订阅,功能类似StreamSubscriptionlisten的组合

      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> {
        Get<T> getState;
        Dispatch dispatch;
        Subscribe subscribe;
        Observable<T> observable;
        ReplaceReducer<T> replaceReducer;
        Future<dynamic> Function() teardown;
        }
        小结: redux/basic.dart主要定义了basic的概念,和一些轻量级的函数

    中间件
    - Middleware: 中间件,返回一个可以合成的Dispatch
    ```dart
    typedef Middleware = Composable Function({
    Dispatch dispatch,
    Get getState,
    });
    typedef StoreCreator = Store Function(
    T preloadedState,
    Reducer reducer,
    );
    typedef StoreEnhancer = StoreCreator Function(StoreCreator creator);

      ```
    

    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的回调事件
      • 通过_FieldsParentChild进行关联

        class _Fields {
        bool isDisposed = false;
        Set<AutoDispose> children;
        AutoDispose parent;
        void Function() onDisposed;
        }
      • 通过visit来实现对上下游想关联的对象遍历操作,和flutter framework中的widget更新时采用visit方式类似,通过visitvisitor方法,利用多态的特性,接耦操作

      • 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个状态appeardisappear

    • Component它作为一个Widget的提供者,通过lifeCycle触发了系列的事件绑定,通过logic的层层抽象,将不同的逻辑分散到不同的抽象层中,处理不同的业务逻辑,以Commpnent为中心

    • 测试Demo: https://gitee.com/jiodg45/study_fish_redux.git

    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.dartReduceEnhancer系列因子进行了大量的reduce,merge,combine操作,在框架内部自动的对分散的逻辑进行集中管理

    • 在widget之间的关系处理上利用DependenciesDependent进行连接,通过Connector来传递不同state的数据. 如下是一次基本的执行过程

  • 相关阅读:
    初步了解软件工程的概念
    实验十四 团队项目评审&课程学习总结
    201671030125 曾佳+《英文文本统计分析》结对项目报告
    201671030125+词频统计软件项目报告
    201671030125 曾佳 + 实验三作业互评与改进报告
    初识 软件工程
    Enjoy Markdown!
    实验十四 团队项目评审&课程学习总结
    201671030127赵津莹 《英文文本统计分析》结对项目报告
    201671030127词频统计软件项目报告
  • 原文地址:https://www.cnblogs.com/wwoo/p/fishredux-yan-jiu.html
Copyright © 2011-2022 走看看