Fish Redux侵入性分析
Fish Redux对于App最大的侵入是每一个页面的结构需按照Redux的流程来组织,如下图所示:
以“我的页面”为例,代码的项目结构如下:
我们逐一分析:
action.dart作为定义动作的类,我们处理某些操作或事件的定义都放在该类中。该类在更换框架后是无法复用的,这个类是Redux框架的特定写法,直接舍弃即可。reducer.dart这个类接收更新视图的操作, 对数据进行修改从而更新视图。这个类也是Redux框架的特定写法,直接舍弃即可。state.dart是组织数据结构的类,是view.dart视图类的数据提供类,因此与view.dart耦合了,更换框架后,state.dart中的数据结构需要保留。view.dart是定义页面视图结构的类,大部分页面代码都可以复用。但控件触发的方法需要更换,页面视图更新的触发也发生了变化。effect.dart是大部分逻辑和业务处理类,大部分代码都是可以复用的,但需要分割到更小的逻辑单元。
-
Component
Fish Redux中Page和Component是整体页面和页面组件的关系。例如ListView和ListViewItem之间的关系,Fish Redux利用Component很好的组织了页面和其组件之间的数据传递关系。这个也是Fish Redux框架的特定写法,更换新的框架后,也无法复用。我们的项目中大量使用了Component,例如首页场站列表、搜索结果列表、广告等等。 -
Global Store
Global Store简单说就是保存全局变量的地方,当全局变量值发生变化时,依赖于全局变量的组件也将发生状态的改变。我们的项目中大量使用了Global Store,例如我的页面中的余额、优惠券、积分等数量的显示。 -
其他
同页面触发方法使用的是dispatch(),跨页面方法调用使用的是broadcast(),这些方法调用都分布在项目各处。
GetX的优点
GetX有一个很大的生态,包括了大型的社区维护,大量的协作者(GitHub 上看有132位),并且承诺只要 Flutter 存在就会继续维护下去。而且 GetX 兼容 Android, iOS, Web, Mac, Linux, Windows多个平台。GetX 甚至还有服务端版本 Get_Server。
GetX 基本上涵盖了 Flutter应用开发的很大一部分,如路由、主题、多语言、弹层、状态管理、依赖注入、网络请求封装等等。GetX看着像一个框架, 但实际上它的各个模块是独立的,其实是一个工具箱。对于开发的时候,可以用它的全家桶,也可以从中任取所需的模块到我们的应用中使用。
GetX 有很多特性,使得编码变得容易。每个特性之间是相互独立的,并且只会在使用的时候才启动。例如,如果仅仅是使用状态管理,那么只有状态管理会被编译。而如果只使用路由,那么状态管理的部分就不会编译。
如何重构和更换框架
- 做一些和框架无关的工作。
- 根据UI统一规范,封装各个页面组件,例如按钮、输入框、弹窗、
Toast等等,不要在页面中写冗余的UI相关代码。颜色、字体、文字等都采用配置文件的方法,不要硬编码在代码中。 - 将业务逻辑代码拆解成最小逻辑单元,以便复用。举个例子:在地图页,从数据库中获取周边场站之后的处理函数有
218行,按顺序分为:计算场站和用户当前位置的距离、取出距离最近的前30条数据、优先显示自营场站、请求桩群状态和免停状态、桩预约状态判断、在地图上绘制marker点。以上步骤都可以封装成独立的逻辑单元,可以复用,避免写出冗余重复的代码。
- 更换
GetX框架
我们先看看使用GetX框架的项目结构:
根据MVC的理论,home_controller.dart就是controller,它是控制器,数据源和逻辑方法都定义在这个文件中。home_page.dart是写该页面布局的地方。而home_binding.dart则是将controller绑定到page上的绑定器,也就是说由home_controller.dart来控制home_page.dart。
- 对照上文对
Fish Redux的分析,将view.dart中代码迁移到page.dart中,effct.dart中代码迁移到controller.dart中。 - 对于
Fish Redux中的Component我们直接弃用即可,将页面组件封装成一个个Widget即可。 - 对于
Fish Redux中的Global Store,我们在GetX中可以定义一个全局的Controller来存放全局变量,用来控制依赖于全局变量的Widget的改变。 - 同页面或者跨页面调用方法,只需要获取到那个页面的
Controller,便可以调用Controller中定义的相关方法。 GetX的路由跳转是它的一大优点,它不依赖于context上下文进行跳转。仅仅需要调用Get.toName('路由名称')就能进行跳转。- 数据驱动
UI的更新,可以在controller中调用update()方法更新GetBuilder包裹的widget。