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 的分发
model
Todo
stores
: Store 模块Store
: Store 抽象基类,需要子类复写其抽象方法onAction()
接收 Dispatcher 分发的 Action 事件,同时持有 Dispatcher,用于分发 storeChangeEventTodoStore
: Todo 业务 Store 实现类,持有业务逻辑数据todos
,并通过onAction(Action action)
接收 Dispatcher 分发的 Action,同时暴漏 View 所需要的数据接口getTodos()
,canUndo()
TodoActivity
TodoRecyclerAdapter
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 的简介。