Flux Demo 源码解析
Flux on Android 的提出者 lgvalle 很早就在 github 上开源了 Flux Demo:
这篇博客将对该项目做一次源码解析。
我的另一篇博客:
包结构

Flux Demo 的包结构相当简洁,文件也不多,除了 View 层的 TodoActivity 与 TodoRecyclerAdapter,model 包下的 Todo,其余 3 个 package 分别对应着 Flux 架构的三个模块 Action,Dispatcher,Store,具体分析如下:
actions: Action 模块Action: Action 实体,由 Action 的唯一标识type与所含数据data组成ActionsCreator: Action 生成器,提供业务逻辑调用,发送 ActionTodoActions: Todo 业务相关 Action 数据
dispatcher: Dispatcher 模块Dispatcher: Action 分发类,内部含有一个bus用于 Action 的分发
modelTodo
stores: Store 模块Store: Store 抽象基类,需要子类复写其抽象方法onAction()接收 Dispatcher 分发的 Action 事件,同时持有 Dispatcher,用于分发 storeChangeEventTodoStore: Todo 业务 Store 实现类,持有业务逻辑数据todos,并通过onAction(Action action)接收 Dispatcher 分发的 Action,同时暴漏 View 所需要的数据接口getTodos(),canUndo()
TodoActivityTodoRecyclerAdapter
UML 类图
类图能很清晰的反映出各个类/模块之间的关系(plantuml 生成的类图一眼看去确实比较乱,建议大家放大查看),与上一篇博客所说的相吻合,类图中可以很清晰的看到 View → ActionsCreator → Action → Dispatcher → Store → storeChangeEvent → View 所形成的闭环。

一次 Flux 闭环
最后我们以 创建一个 Todo 事项 举例来说明 Flux 架构的工作流程,并分析具体的代码实现。
- TodoActivity.java → 用户输入
- TodoActivity.java → 用户点击创建按钮
- TodoActivity.java → 调用方法
addTodo() - TodoActivity.java → 调用 ActionsCreator 的方法
create(String text),传入用户输入内容 - ActionsCreator.java → 调用 Dispatcher 的方法
dispatch(String type, Object... data)
- 传入 Action 的 key(type),标识这个 Action 是创建操作的
TodoActions.TODO_CREATE,以及 Action 的 data,即TodoActions.KEY_TEXT与text这对 key-value - 在 dispatch 方法中会将传入的 Action 相关数据组装成一个 Action 对象
- ActionsCreator.java → 调用 Dispatcher 的方法
post(final Object event),传入上一步组装好的 Action 对象 - Dispatcher.java → 调用 Bus 的方法
post(Object event),传入 Action 对象,这里是通过 otto 库发送了 Action - TodoStore.java →
onAction(Action action)接收到 Bus 发送的 Action 对象,根据action.getType()判断要做的操作为TodoActions.TODO_CREATE - TodoStore.java → 执行
create(String text)方法创建一个 Todo 对象,添加到todos数据集中,方法接收的 text 参数是通过 Action 对象得到的,记得我们在第 5 步时将text组装到了 Action 对象中 - Store.java → 执行
emitStoreChange() - Store.java → 调用 Dispatcher 的方法
emitChange(Store.StoreChangeEvent o),传入通过changeEvent()方法生成的 StoreChangeEvent 对象,在这个例子中 TodoStore 类重写了changeEvent()方法,返回 TodoStoreChangeEvent 对象 - Dispatcher.java → 调用 Bus 的方法
post(Object event),传入第 11 步传入的 StoreChangeEvent 对象,这里是通过 otto 库发送了 StoreChangeEvent - TodoActivity.java →
onTodoStoreChange(TodoStore.TodoStoreChangeEvent event)方法接收到 Bus 发送的 TodoStoreChangeEvent 对象 - 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 的简介。