編輯:關於Android編程
Flux 架構介紹
Flux 架構 被Facebook使用來構建他們的客戶端web應用。跟Clean Architecture一樣,它不是為移動應用設計的,但是它的特性和簡單可以讓我們很好的在安卓項目中采用。
Flux模式最大的特點是單向的數據流,它的UI狀態更新模式繼承了MVC模式的設計思想。Flux並不是具體的框架,而是一套處理UI問題的模式,Android Flux同樣不是具體的框架,你不需要導入或者集成任何新的代碼就可以使用,而你需要做的事情是了解這套思想、遵循這種開發模式,查看我們提供的Android代碼示例,寫自己的代碼。
要理解Flux,有兩個關鍵的特點
1、數據流總是單向的
一個單向的數據流 是 Flux 架構的核心,也是它簡單易學的原因。就如下面討論的,在進行應用測試的時候,它提供了非常大的幫助。
2、應用被分成三個主要部分:
. View: 應用的界面。這裡創建響應用戶操作的action
。
. Dispatcher: 中心樞紐,傳遞所有的action
,負責把它們運達每個Store
。
. Store: 維護一個特定application domain
的狀態。它們根據當前狀態響應action
,執行業務邏輯,同時在完成的時候發出一個change
事件。這個事件用於view
更新其界面。
這三個部分都是通過Action
來通信的:一個簡單的基本對象,以類型來區分,包含了和操作相關的數據。
Flux Android 架構
在安卓開發中使用Flux設計規范的目的是建立一個在簡單性與易擴展易測試之間都比較平衡的架構。
第一步是找到Flux元素和安卓app組件之間的映射。
其中兩個元素非常容易找到與實現。
View: Activity o
或者Fragment
Dispatcher:
一個事件總線( event bus),在我的例子中將使用Otto,但是其它任何實現都應該是ok的。
Actions
Actions
也不復雜。它們的實現和POJO
一樣簡單,有兩個主要屬性:
1、Type: 一個String,定義了事件的類型。
2、Data: 一個map,裝載了本次操作。
Store是Flux理論中最難的部分。
Stores
響應Dispatcher
發出的Action
,執行業務邏輯並發送change
事件。Stores
的唯一輸出是這單一的事件:change
。其它對Store
內部狀態感興趣的組件必須監聽這個事件,同時使用它獲取需要的數據。最後,stores
必須對外公開一個獲取application
狀態的接口。這樣,view
元素可以查詢Stores
然後相應的更新UI。
這裡通過一個簡單的小demo來講述整個流程。我們的界面上有一個Button
和一個TextView
,點擊Button
後讓TextView
顯示出文字。常規的實現,直接在Activity
中完成邏輯,MVP
模式,在Presenter
層來進行,對於Flux架構,我們要怎麼實現呢。通過上圖我們可以看到,View
會產生Action
,然後被Dispatcher
進行調度,經過Store
相應處理,將數據顯示出來。
如何產生Action
首先要知道Action
是什麼樣
public class Action { private final String type; private final HashMap<String, Object> data; public Action(String type, HashMap<String, Object> data) { this.type = type; this.data = data; } public static Builder type(String type) { return new Builder().with(type); } public String getType() { return type; } public HashMap getData() { return data; } public static class Builder { private String type; private HashMap<String, Object> data; Builder with(String type) { if(type == null) { throw new IllegalArgumentException("Type may not be null."); } this.type = type; this.data = new HashMap<>(); return this; } public Builder bundle(String key, Object value) { if (key == null) { throw new IllegalArgumentException("Key may not be null."); } if(value == null) { throw new IllegalArgumentException("Value may not be null."); } data.put(key, value); return this; } public Action build() { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("At least one key is required."); } return new Action(type, data); } } }
每一個Action
有兩個屬性,一個來標記Type
,另一個字段來存儲傳送的數據,通過Map
來存放。
對於Action Type
,我們可以通過一個接口或者類來進行記錄,將所有的類型保存在其中。方便我們的調用。
public interface ShowActions { String TODO_SHOW = "todo-show"; String GET_TEXT = "get-text"; }
如何創建Action
,定義一個類,專門用來根據我們可能會出現的各種View
的事件,定義出來各種Action
。
public class ActionsCreator { private static ActionsCreator instance; final Dispatcher mDispatcher; ActionsCreator(Dispatcher dispatcher){ mDispatcher = dispatcher; } public static ActionsCreator get(Dispatcher dispatcher) { if (instance == null) { instance = new ActionsCreator(dispatcher); } return instance; } public void create(String text) { mDispatcher.dispatch(ShowActions.TODO_SHOW, ShowActions.GET_TEXT, text); }
在我們准備用ActionsCreator
來創建Action
的時候,我們並沒有直接new Action
這種方式來做,而是將其通過調度器,對其進行了分發。這裡的事件分發,我們使用的是Otto
的Bus
來進行事件的分發。
public class Dispatcher { private final Bus bus; private static Dispatcher instance; Dispatcher(Bus bus){ this.bus = bus; } public static Dispatcher get(Bus bus) { if (instance == null) { instance = new Dispatcher(bus); } return instance; } public void register(final Object cls) { bus.register(cls); } public void unRegister(final Object cls) { bus.unregister(cls); } public void emitChange(Store.StoreChangeEvent o) {post(o);} public void dispatch(String type, Object... data) { if(TextUtils.isEmpty(type)) { throw new IllegalArgumentException("Type must not be empty"); } if (data.length % 2 != 0) { throw new IllegalArgumentException("Data must be a valid list of key"); } Action.Builder actionBuilder = Action.type(type); for (int i = 0; i < data.length; i++) { String key = (String) data[i++]; Object value = data[i++]; actionBuilder.bundle(key, value); } post(actionBuilder.build()); } private boolean isEmpty(String type) { return TextUtils.isEmpty(type); } private void post(final Object event) { bus.post(event); } }
在調度的過程中,我們將傳遞進來的數據進行一個解析,然後根據數據創建出相應的Action
,然後對Action
進行分發,這個時候關注了相應的Action
的Store
就會開始根據相應的Action
開始執行相應的操作。在Store
中,聲明了一個抽象方法onAction
來負責進行對於Action
的判斷和分發,然後定義了StoreChangeEvent
接口作為事件變化,當有變化的時候,通過這個進行傳遞,我們可以自己實現這個接口,然後在裡面添加一些方法和字段用來攜帶數據。
public abstract class Store { final Dispatcher mDispatcher; protected Store(Dispatcher dispatcher) { this.mDispatcher = dispatcher; } void emitStoreChange() { mDispatcher.emitChange(changeEvent()); } abstract StoreChangeEvent changeEvent(); public abstract void onAction(Action action); public interface StoreChangeEvent {} }
我們自定義的Store類
public class ShowStore extends Store { private static ShowStore instance; private String showText; public ShowStore(Dispatcher dispatcher){ super(dispatcher); } public static ShowStore get(Dispatcher dispatcher) { if (instance == null) { instance = new ShowStore(dispatcher); } return instance; } @Subscribe public void onAction(Action action) { switch (action.getType()) { case ShowActions.TODO_SHOW : showText = ((String)action.getData().get(ShowActions.GET_TEXT)); Log.i("showText", showText); emitStoreChange(); break; default: break; } } public String getShowText(){ return showText; } @Override StoreChangeEvent changeEvent() { return new ShowChangeEvent(); } public class ShowChangeEvent implements StoreChangeEvent { } }
然後我們在View
也就是Activity
中訂閱了變化時間的方法,這個時候就可以實現對於View
中的數據的一個動態更新。
@Subscribe public void showText (ShowStore.ShowChangeEvent event){ mTextView.setText(mShowStore.getShowText()); }
總結
通過Flux架構,使用的流程是,我們的View的事件會攜帶數據,通過一個ActionsCreate創建一個Type的Action,實際完成過程是在Dispatcher的dispatch中,然後再將這個Action丟給訂閱了該Action的Store方法中,在這裡完成各種邏輯,處理,甚至是可以發起網絡請求獲取數據,處理完成,可以將結果封裝成一個事件,然後這個事件會再次通過調度器中的emitChangeEvent將事件傳遞給訂閱了該事件的函數,而這個接收響應事件的函數被我們定義在我們View中,從而實現對於我們View的更新。以上就是本文的全部內容了,希望本文的內容對大家學習Flux架構有所幫助。
最近我獨立開發的項目《全醫會》已經在內測當中了,很快將會上架到各大應用市場。之前開發的幾個項目都因為一些原因沒有上架還是比較遺憾的。所以,最近我心情格外的好。 今天在做
1、checkbox(復選框)checkbox常用於多選的情況,比如批量刪除、添加群聊等;DOM結構 checkbox示例 默認checkbox在右側顯示
1、 題外話 相信大家對LayoutInflate都不陌生,特別在ListView的Adapter的getView方法中基本都會出現,使用
最近要做一個輪播圖的效果,網上看了幾篇文章,基本上都能找到實現,效果還挺不錯,但是在寫的時候感覺每次都要單獨去重新在Activity裡寫一堆代碼。於是自己封裝了一下。本篇