Flux Demo 源码解析

Flux on Android 的提出者 lgvalle 很早就在 github 上开源了 Flux Demo:

https://github.com/lgvalle/android-flux-todo-app

这篇博客将对该项目做一次源码解析。

我的另一篇博客:

Flux 架构简析

包结构

Flux Package Architecture

Flux Demo 的包结构相当简洁,文件也不多,除了 View 层的 TodoActivityTodoRecyclerAdapter,model 包下的 Todo,其余 3 个 package 分别对应着 Flux 架构的三个模块 ActionDispatcherStore,具体分析如下:

  • actions : Action 模块
    • Action : Action 实体,由 Action 的唯一标识 type 与所含数据 data 组成
    • ActionsCreator : Action 生成器,提供业务逻辑调用,发送 Action
    • TodoActions : Todo 业务相关 Action 数据
  • dispatcher : Dispatcher 模块
    • Dispatcher : Action 分发类,内部含有一个 bus 用于 Action 的分发
  • model
    • Todo
  • stores : Store 模块
    • Store : Store 抽象基类,需要子类复写其抽象方法 onAction() 接收 Dispatcher 分发的 Action 事件,同时持有 Dispatcher,用于分发 storeChangeEvent
    • TodoStore : Todo 业务 Store 实现类,持有业务逻辑数据 todos,并通过 onAction(Action action) 接收 Dispatcher 分发的 Action,同时暴漏 View 所需要的数据接口 getTodos()canUndo()
  • TodoActivity
  • TodoRecyclerAdapter

UML 类图

类图能很清晰的反映出各个类/模块之间的关系(plantuml 生成的类图一眼看去确实比较乱,建议大家放大查看),与上一篇博客所说的相吻合,类图中可以很清晰的看到 ViewActionsCreatorActionDispatcherStorestoreChangeEventView 所形成的闭环。

Flux UML Class

一次 Flux 闭环

最后我们以 创建一个 Todo 事项 举例来说明 Flux 架构的工作流程,并分析具体的代码实现。

  1. TodoActivity.java → 用户输入
  2. TodoActivity.java → 用户点击创建按钮
  3. TodoActivity.java → 调用方法 addTodo()
  4. TodoActivity.java → 调用 ActionsCreator 的方法 create(String text),传入用户输入内容
  5. ActionsCreator.java → 调用 Dispatcher 的方法 dispatch(String type, Object... data)
  • 传入 Action 的 key(type),标识这个 Action 是创建操作的 TodoActions.TODO_CREATE,以及 Action 的 data,即 TodoActions.KEY_TEXTtext 这对 key-value
  • 在 dispatch 方法中会将传入的 Action 相关数据组装成一个 Action 对象
  1. ActionsCreator.java → 调用 Dispatcher 的方法 post(final Object event),传入上一步组装好的 Action 对象
  2. Dispatcher.java → 调用 Bus 的方法 post(Object event),传入 Action 对象,这里是通过 otto 库发送了 Action
  3. TodoStore.java → onAction(Action action) 接收到 Bus 发送的 Action 对象,根据 action.getType() 判断要做的操作为 TodoActions.TODO_CREATE
  4. TodoStore.java → 执行 create(String text) 方法创建一个 Todo 对象,添加到 todos 数据集中,方法接收的 text 参数是通过 Action 对象得到的,记得我们在第 5 步时将 text 组装到了 Action 对象中
  5. Store.java → 执行 emitStoreChange()
  6. Store.java → 调用 Dispatcher 的方法 emitChange(Store.StoreChangeEvent o),传入通过 changeEvent() 方法生成的 StoreChangeEvent 对象,在这个例子中 TodoStore 类重写了 changeEvent() 方法,返回 TodoStoreChangeEvent 对象
  7. Dispatcher.java → 调用 Bus 的方法 post(Object event),传入第 11 步传入的 StoreChangeEvent 对象,这里是通过 otto 库发送了 StoreChangeEvent
  8. TodoActivity.java → onTodoStoreChange(TodoStore.TodoStoreChangeEvent event) 方法接收到 Bus 发送的 TodoStoreChangeEvent 对象
  9. TodoActivity.java → 执行 updateUI() 从 TodoStore 获取数据(第 9 步时更新了 TodoStore 中的数据)更新界面

小结

一次简单的创建 Todo 的过程被我们拆解成出 14 个步骤,看起来很麻烦,但不难从中发现 Flux 架构极的单向数据流传输与可定制性。我们在 ActionsCreator 中对处理各种各样的业务逻辑,根据结果分发不同的 Action,每一个 Action 对应的都是一条干净,清晰,完整的数据流传递。我们在 Store 中针对 Action 响应数据更新,最后再通知 View 更新,这个过程中也存在强大的可定制性,比如在上面的例子中,我们创建完成后提交的 StoreChangeEvent 不再是通用的 TodoStoreChangeEvent,而是针对 TODO_CREATE Action 发送特定的 TodoCreateStoreChangeEvent,View 层响应 TodoCreateStoreChangeEvent 执行的操作则是从 TodoStore 中取出最新的一条数据,调用 notifyItemInserted 动态的添加到 View 界面,这样用户体验无疑会好很多。

Flux 架构的特点与优势在于 闭环单向数据流,在 Flux 架构上写业务是一个通畅的过程,但 Flux 的定位还是与 MVP 类似,只是业务逻辑层的架构,如果放在当前大热的 CleanArchitecture 中,仅相当于 presentation 这一层,domain 层与 data 层则不是 Flux 关心的事情,或许后面会写一篇关于 CleanArchitecture 的简介。