本文的合集已經編著成書,高級Android開發強化實戰,歡迎各位讀友的建議和指導。在京東即可購買:https://item.jd.com/12385680.html
任何架構最終目的都是讓程序更加有序, 功能便于擴展, Bug容易追蹤.
Facebook使用Flux架構來構建客戶端的Web應用. Flux架構并不是為移動端設計的, 但是我們仍然可以采用這個思想在Android端使用. Flux是數據驅動型架構, 在以數據為核心的場景中使用非常合適, 不過Facebook好像把Flux架構應用于所有產品, 無論是前端還是移動端. 最新Facebook開發的ReactNative中, 就是使用Flux架構為核心, 也是開源的, 可以閱讀RN的代碼了解所有內容.
Flux架構, 顧名思義表示流, 是以數據流為基礎.
本文源碼的Github下載地址
基本架構模型如圖:
模型主要分為四個模塊:
(1) View: 視圖, 根據用戶交互(Use Interaction)的內容創建響應事件, 調用活動創建器(ActionCreator)的方法, 發送響應用戶操作的事件.
(2) ActionCreator: 活動創建器, 把活動的類型和數據發送給調度器(Dispatcher), 根據類型和數據創建活動(Action). 也可以進行網絡操作(WebApi), 完成后, 再發送數據.
(3) Dispatcher: 調度器, 把接收到的活動, 通過總線(EventBus), 把活動發送出去, 由存儲器(Store)根據活動的類型和數據, 修改數據模型.
(4) Store: 存儲器, 維護特定的數據狀態, 接收總線分發的活動, 根據活動類型執行不同的業務邏輯. 在完成時, 發出數據修改(ChangeEvent)的事件, 視圖監聽這一事件, 更新顯示內容.
Talk is cheap, show you the code.
只有通過代碼才能真正的了解架構的意義, 我寫了一個基于Flux架構的ToDoList.
頁面發送各種增刪改查的事件, 通過Flux模型, 修改本地存儲的數據, 再反饋回頁面.
1. 視圖(View)
視圖(View): 視圖是一個Activity, 負責響應用戶交互(Use Interaction)的事件, 發送到給活動創建器(ActionCreator); 同時接收修改數據(ChangeEvent)事件, 更新頁面.
public class MainActivity extends AppCompatActivity {
// ...
// 添加數據
@OnClick(R.id.main_add) void addItem() {
addTodo(); // 添加TodoItem
resetMainInput(); // 重置輸入框
}
// 選中數據
@OnClick(R.id.main_checkbox) void checkItem() {
checkAll(); // 所有Item項改變選中狀態
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // 設置Layout
ButterKnife.bind(this); // 綁定ButterKnife
initDependencies(); // 創建Flux的核心管理類
// 設置RecyclerView
mMainList.setLayoutManager(new LinearLayoutManager(this));
mListAdapter = new RecyclerAdapter(sActionsCreator);
mMainList.setAdapter(mListAdapter);
}
// 初始化: Dispatcher調度器, Action事件, Store狀態
private void initDependencies() {
sDispatcher = Dispatcher.getInstance(new Bus());
sActionsCreator = ActionsCreator.getInstance(sDispatcher);
sTodoStore = TodoStore.getInstance(sDispatcher);
}
@Override
protected void onResume() {
super.onResume();
// 把訂閱接口注冊到EventBus
sDispatcher.register(this);
sDispatcher.register(sTodoStore);
}
@Override
protected void onPause() {
super.onPause();
// 解除訂閱接口
sDispatcher.unregister(this);
sDispatcher.unregister(sTodoStore);
}
// 改變改變所有狀態(ActionsCreator)
private void checkAll() {
sActionsCreator.toggleCompleteAll();
}
// 清理選中的項(ActionsCreator)
private void clearCompleted() {
sActionsCreator.destroyCompleted();
}
// ...
// 接收事件的改變
@Subscribe
public void onTodoStoreChange(TodoStore.TodoStoreChangeEvent event) {
updateUI();
}
// 更新UI, 核心方法
private void updateUI() {
// 設置適配器數據, 每次更新TodoStore的狀態
mListAdapter.setItems(sTodoStore.getTodos());
...
}
}
代碼比較長, 只截取了一部分. 其中View的核心部分:
(1) 活動創建器(ActionsCreator), 負責響應用戶交互事件, 如checkAll()等.
(2) 接收狀態修改(onTodoStoreChange), 負責接收存儲器(Store)修改完成的數據, 并更新頁面(updateUI).
2. 活動創建器(ActionsCreator)
活動創建器(ActionsCreator): 主要負責根據響應事件的類型和數據, 發送相應的活動到調度器(Dispatch). 也可以發送網絡請求(WebApi), 獲取異步數據, 完成后再發送.
public class ActionsCreator {
private static ActionsCreator sInstance;
private final Dispatcher mDispatcher;
private ActionsCreator(Dispatcher dispatcher) {
mDispatcher = dispatcher;
}
public static ActionsCreator getInstance(Dispatcher dispatcher) {
if (sInstance == null) {
sInstance = new ActionsCreator(dispatcher);
}
return sInstance;
}
public void create(String text) {
mDispatcher.dispatch(TodoActions.TODO_CREATE, TodoActions.KEY_TEXT, text);
}
public void destroy(long id) {
mDispatcher.dispatch(TodoActions.TODO_DESTROY, TodoActions.KEY_ID, id);
}
// ...
}
活動在調度器(Dispatcher)中創建.
活動創造器(ActionsCreator), 第一個參數是類型, 其余參數是數據, 即配對的Key-Value.
3. 調度器(Dispatcher)
調度器(Dispatcher), 是事件分發的中心, 使用事件總線(EventBus), 發送活動到存儲器(Store). 存儲器根據活動的類型和數據, 進行處理.
public class Dispatcher {
private final Bus mBus;
private static Dispatcher sInstance;
private Dispatcher(Bus bus) {
mBus = bus;
}
public static Dispatcher getInstance(Bus bus) {
if (sInstance == null) {
sInstance = new Dispatcher(bus);
}
return sInstance;
}
public void register(final Object cls) {
mBus.register(cls);
}
public void unregister(final Object cls) {
mBus.unregister(cls);
}
private void post(final Object event) {
mBus.post(event);
}
// 每個狀態改變都需要發送事件, 由View相應, 做出更改
public void emitChange(Store.StoreChangeEvent o) {
post(o);
}
/**
* 調度核心函數
*
* @param type 調度類型
* @param data 數據(Key, Value)
*/
public void dispatch(String type, Object... data) {
if (type == null || type.isEmpty()) { // 數據空
throw new IllegalArgumentException("Type must not be empty");
}
if (data.length % 2 != 0) { // 非Key-Value
throw new IllegalArgumentException("Data must be a valid list of key,value pairs");
}
Action.Builder actionBuilder = Action.type(type);
int i = 0;
while (i < data.length) {
String key = (String) data[i++];
Object value = data[i++];
actionBuilder.bundle(key, value); // 放置鍵值
}
// 發送到EventBus
post(actionBuilder.build());
}
}
調度器使用事件總線(EventBus)分發數據, 有兩個核心部分:
(1) dispatch(): 把類型和數據組成活動(Action), 發送至事件總線(EventBus), 由存儲器(Store)負責處理.
(2) emitChange(): 把存儲器(Store)處理完的狀態和數據, 發送修改通知至事件總線(EventBus), 提示視圖(View)進行更新頁面(UpdateUI).
4. 存儲器(Store)
存儲器(Store): 負責存儲數據和狀態, 接收事件總線(EventBus)上的修改通知, 根據類型, 修改數據和狀態. 也可以使用數據庫和本地存儲.
public class TodoStore extends Store {
private static TodoStore sInstance; // 單例
private final List<Todo> mTodos; // 數據
private Todo lastDeleted; // 狀態: 最近一次刪除數據
private TodoStore(Dispatcher dispatcher) {
super(dispatcher);
mTodos = new ArrayList<>();
}
public static TodoStore getInstance(Dispatcher dispatcher) {
if (sInstance == null) {
sInstance = new TodoStore(dispatcher);
}
return sInstance;
}
@Override
@Subscribe
public void onAction(Action action) {
long id;
switch (action.getType()) {
case TodoActions.TODO_CREATE:
String text = ((String) action.getData().get(TodoActions.KEY_TEXT));
create(text);
emitStoreChange(); // 發生改變事件
break;
case TodoActions.TODO_DESTROY:
id = ((long) action.getData().get(TodoActions.KEY_ID));
destroy(id);
emitStoreChange();
break;
case TodoActions.TODO_UNDO_DESTROY:
undoDestroy();
emitStoreChange();
break;
// ...
}
}
private void destroyCompleted() {
Iterator<Todo> iter = mTodos.iterator();
while (iter.hasNext()) {
Todo todo = iter.next();
if (todo.isComplete()) {
iter.remove();
}
}
}
// ...
@Override
public StoreChangeEvent changeEvent() {
return new TodoStoreChangeEvent();
}
}
存儲器(Store)的核心是onAction()方法, 獲得事件總線(EventBus)的通知, 修改數據, 完成后調用emitStoreChange()方法, 通知視圖(View)進行數據更新(UpdateUI).
整套的循環邏輯都已經完成, 清晰可見, 這就是架構的好處吧.
Flux: View -> Action -> Dispatcher -> Store -> View.
OK, that's all! Enjoy it!