背景在使用Flutter开发的过程中,我们遇到了业务代码耦合严重,代码可维护性差,比如泥泞。对于闲鱼这样负责任的业务场景,我们需要一个统一的应用框架来摆脱目前的发展困境,而这也是Flutter领域的一个空缺。FishRedux是解决上述问题的上层应用框架。是一个基于Redux数据管理的组装式flutter应用框架,特别适合构建中大型复杂应用。其主要特点是组态汇编。一方面,它将一个大的页面、视图和数据层拆解成独立的Component|Adapter。上层负责组装,下层负责实现。分为View、Reducer、Effect等独立的context-free函数。所以它会非常干净,易于编写,易于维护,易于协作。FishRedux主要受到Redux、React、Elm、Dva等优秀框架的启发。FishRedux站在巨人的肩膀上,将集中化、分裂、复用和隔离更进了一步。分层架构图在架构图中,主体从下到上分为三层。每一层用来解决不同层次的问题和矛盾,下面依次展开。ReduxRedux是来自前端社区的数据管理框架。Native开发的同学可能有点陌生。让我们做一个简单的介绍。Redux是做什么的?Redux是一个可预测且易于调试的数据管理框架。数据的增删改查等所有操作都由Redux统一负责。Redux是如何设计和实现的?Redux是一个功能性的数据管理框架。传统的数据管理OOP往往会定义一些Bean,每个Bean都会暴露一些Public-API来操作内部数据(拥塞模型)。功能方法是添加一个抽象维度。数据的定义是一些Struct(贫血模型),操作数据的方法统一到Reducers中,具有相同的函数签名(T,Action)=>T。FP:Struct(贫血模型)+Reducer=OOP:Bean(拥塞模型)同时,Redux加入了FP常用的中间件(AOP)模式和订阅机制,为框架带来了极高的灵活性和可扩展性。贫血模型、充血模型参考:[https://en.wikipedia.org/wiki/Plain_old_Java_object](https://en.wikipedia.org/wiki/Plain_old_Java_object)Redux的缺点Redux核心只关心数据管理,不具体什么场景用它,这是它的优势也是它的劣势。在我们实际使用Redux的过程中,面临两个具体的问题:Redux的中心化和Component的划分之间的矛盾。Redux的Reducer需要逐层手工组装,带来了繁琐和易错的问题。FishRedux的改进版FishRedux使用Redux来做集中的可观察数据管理。不仅如此,针对传统Redux在使用层面的不足,我们在开发并排Flutter页面的场景中,通过更好更高的抽象对其进行了改进。一个组件需要定义一个数据(Struct)和一个Reducer。同时,组件之间存在父依赖关系。通过这一层依赖关系,我们解决了【集中】和【分而治之】的矛盾。同时reducer的手动逐层combine由框架自动完成,大大简化了Redux的使用难度。我们得到了理想的集中效果和分而治之的代码。以上社区标准的followState、Action、Reducer、Store、Middleware等概念与社区的ReduxJS完全一致。我们将保留Redux的所有优点。如果想对Redux有更深入的了解,请参考https://github.com/reduxjs/reduxComponent组件是对部分显示和功能的封装。基于Redux的原理,我们将函数细分为修改数据的函数(Reducer)和不修改数据的函数(sideeffects)。于是我们得到了View、Effect、Reducer三个部分,它们被称为组件的三要素,分别负责组件的显示、未修改数据的行为、修改数据的行为。这是一场既面向现在又面向未来的分裂。从现在的Redux来看,就是数据管理等。在面向未来的UI自动化中,外观是UIExpressive和其他。UI的表达对于程序员来说即将进入黑盒时代,研发工程师将更加关注非修改数据行为和修改数据行为。组件分而治之的视图以及分而治之的数据。通过逐层分治,我们将复杂的页面和数据分割成独立的小模块。这将促进团队内部的协作开发。关于ViewView只是一个函数签名:(T,Dispatch,ViewService)=>Widget主要包含三个方面的信息View是完全由数据驱动的。视图生成的事件/回调通过Dispatch发送“意图”,无需具体实现。需要使用的组件依赖等,通过ViewService标准化调用。比如一个典型的符合View签名的函数关于EffectEffect是非修改数据的标准定义behavior,也就是一个函数签名:(Context,Action)=>Object主要包括接收来自View的“intent”四个方面的信息,还包括相应的生命周期回调,然后进行具体的执行。它的处理可能是一个异步函数,在这个过程中可能会修改数据,所以我们不提倡持有数据,而是通过上下文获取新的数据。它不会修改数据。如果需要修改,需要发送一个Action给Reducer处理。它的返回值仅限于bool或Future,对应支持同步函数和协程的处理流程。例如:良好的协程支持关于ReducerReducer是一个完全符合Redux规范的函数签名:(T,Action)=>TSomeReducers在符合签名的同时,我们通过显式配置完成大组件所依赖的小组件和适配器的注册。这种依赖配置称为Dependencies。于是就有了这样一个公式Component=View+Effect(可选)+Reducer(可选)+Dependencies(可选)。一个典型的组装通过Component的抽象,我们得到了完整的分治,多维复用,更好的解耦。AdapterAdapter也是对部分显示和功能的封装。它是为ListView的高性能场景而生,是Component实现上的一次变革。它的目标是解决Component模型在flutter-ListView场景下的三个问题1)在Component中放一个“Big-Cell”无法享受ListView代码的性能优化。2)组件无法区分appear|disappear和init|dispose。3)Effect的生命周期与View的耦合在ListView场景下不符合直观预期。简单的说,我们想要一个逻辑的ScrollView和一个性能的ListView,这样一种局部展示和功能封装的抽象。做这样一个独立的抽象层,我们来看看实际效果。我们页面不使用frame,使用frameComponent,使用frameComponent+Adapter性能基线对比Reducer是long-live,Effect是medium-live,View是short-live。我们通过不断的测试来对比,以安卓机为例:我们的详情页在使用框架之前的FPS,baseline是52FPS。使用框架,只使用Component抽象,FPS掉到40,遇到“Big-Cell”陷阱。使用框架并同时使用Adapter抽象后,FPS增加到53,回到baseline之上,有小幅提升。Directory推荐的目录结构会是这样的sample_page--action.dart--page.dart--view.dart--effect.dart--reducer.dart--state.dartcomponentssample_component--action.dart--component。dart--view.dart--effect.dart--reducer.dart--state.dart上层负责组装,下层负责实现,会有一个插件提供给我们填充很快。以闲鱼的详细场景为例:组件之间是完全独立的,组件与容器之间也是相互独立的。通信机制组件|适配器内通信组件|适配器间通信简单描述:采用Prioritizedbroadcast,自首播。发送的Action首先要自己处理,否则会广播给其他组件和Redux处理。最终,我们通过简单直观的dispatch完成了组件内部以及组件之间(父子、子子与父、兄弟等)的所有通信需求。刷新机制数据刷新部分数据修改,自动逐层触发上层数据浅拷贝,对上层业务代码透明。逐层拷贝数据,一方面是对Redux数据修改的严格遵循。另一方面也是对数据驱动展示的严格遵循。查看刷新平面通知给所有组件,组件通过shouldUpdate判断是否需要刷新优点数据集中管理通过Redux集中和可观察的数据管理。我们将原样保留Redux的所有优点,同时Reducer的合并由框架代理自动完成,大大简化了使用Redux的繁琐。组件分而治之管理组件分而治之的不仅是视图,还有数据。通过逐层分治,我们将复杂的页面和数据分割成独立的小模块。这将促进团队内部的协作开发。View、Reducer、EffectIsolation将组件拆分为三个无状态且独立的功能。因为是无状态函数,所以更容易编写、调试、测试和维护。同时也带来了更多的组合、再利用和创新的可能性。声明式配置组装组件和适配器通过自由声明式配置组装完成。包括它的View、Reducer、Effect及其依赖的子项。良好的可扩展性核心框架保持其核心三层聚焦,不做核心聚焦之外的任何事情,并为上层保持灵活的可扩展性。该框架甚至没有一行打印代码,但我们可以通过标准的中间件观察数据的流动和组件的变化。除了核心的三层框架之外,还可以通过dart的语言特性为Component或Adapter添加mixins,灵活组合地增强其上层使用的定制化和能力。框架与其他中间件的连接,如自动暴露、高可用等,在各个中间件与框架之间是透明的,由上层自由组装。Small,Simple,Complete它非常小,仅包含1000多行代码。使用简单,完成几个小功能,组装完成,即可运行。它是完整的。FishRedux已经在阿里闲鱼技术团队的多个场景进行了应用。
