Android學(xué)習(xí)之Flux架構(gòu)入門
Flux 架構(gòu)介紹
Flux 架構(gòu) 被Facebook使用來構(gòu)建他們的客戶端web應(yīng)用。跟Clean Architecture一樣,它不是為移動(dòng)應(yīng)用設(shè)計(jì)的,但是它的特性和簡(jiǎn)單可以讓我們很好的在安卓項(xiàng)目中采用。
Flux模式最大的特點(diǎn)是單向的數(shù)據(jù)流,它的UI狀態(tài)更新模式繼承了MVC模式的設(shè)計(jì)思想。Flux并不是具體的框架,而是一套處理UI問題的模式,Android Flux同樣不是具體的框架,你不需要導(dǎo)入或者集成任何新的代碼就可以使用,而你需要做的事情是了解這套思想、遵循這種開發(fā)模式,查看我們提供的Android代碼示例,寫自己的代碼。

要理解Flux,有兩個(gè)關(guān)鍵的特點(diǎn)
1、數(shù)據(jù)流總是單向的
一個(gè)單向的數(shù)據(jù)流 是 Flux 架構(gòu)的核心,也是它簡(jiǎn)單易學(xué)的原因。就如下面討論的,在進(jìn)行應(yīng)用測(cè)試的時(shí)候,它提供了非常大的幫助。
2、應(yīng)用被分成三個(gè)主要部分:
. View: 應(yīng)用的界面。這里創(chuàng)建響應(yīng)用戶操作的action。
. Dispatcher: 中心樞紐,傳遞所有的action,負(fù)責(zé)把它們運(yùn)達(dá)每個(gè)Store。
. Store: 維護(hù)一個(gè)特定application domain的狀態(tài)。它們根據(jù)當(dāng)前狀態(tài)響應(yīng)action,執(zhí)行業(yè)務(wù)邏輯,同時(shí)在完成的時(shí)候發(fā)出一個(gè)change事件。這個(gè)事件用于view更新其界面。
這三個(gè)部分都是通過Action來通信的:一個(gè)簡(jiǎn)單的基本對(duì)象,以類型來區(qū)分,包含了和操作相關(guān)的數(shù)據(jù)。
Flux Android 架構(gòu)
在安卓開發(fā)中使用Flux設(shè)計(jì)規(guī)范的目的是建立一個(gè)在簡(jiǎn)單性與易擴(kuò)展易測(cè)試之間都比較平衡的架構(gòu)。
第一步是找到Flux元素和安卓app組件之間的映射。
其中兩個(gè)元素非常容易找到與實(shí)現(xiàn)。
View: Activity o或者Fragment
Dispatcher: 一個(gè)事件總線( event bus),在我的例子中將使用Otto,但是其它任何實(shí)現(xiàn)都應(yīng)該是ok的。
Actions
Actions也不復(fù)雜。它們的實(shí)現(xiàn)和POJO一樣簡(jiǎn)單,有兩個(gè)主要屬性:
1、Type: 一個(gè)String,定義了事件的類型。
2、Data: 一個(gè)map,裝載了本次操作。
Store是Flux理論中最難的部分。
Stores響應(yīng)Dispatcher發(fā)出的Action,執(zhí)行業(yè)務(wù)邏輯并發(fā)送change事件。Stores的唯一輸出是這單一的事件:change。其它對(duì)Store內(nèi)部狀態(tài)感興趣的組件必須監(jiān)聽這個(gè)事件,同時(shí)使用它獲取需要的數(shù)據(jù)。最后,stores必須對(duì)外公開一個(gè)獲取application狀態(tài)的接口。這樣,view元素可以查詢Stores然后相應(yīng)的更新UI。
這里通過一個(gè)簡(jiǎn)單的小demo來講述整個(gè)流程。我們的界面上有一個(gè)Button和一個(gè)TextView,點(diǎn)擊Button后讓TextView顯示出文字。常規(guī)的實(shí)現(xiàn),直接在Activity中完成邏輯,MVP模式,在Presenter層來進(jìn)行,對(duì)于Flux架構(gòu),我們要怎么實(shí)現(xiàn)呢。通過上圖我們可以看到,View會(huì)產(chǎn)生Action,然后被Dispatcher進(jìn)行調(diào)度,經(jīng)過Store相應(yīng)處理,將數(shù)據(jù)顯示出來。
如何產(chǎn)生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);
}
}
}
每一個(gè)Action有兩個(gè)屬性,一個(gè)來標(biāo)記Type,另一個(gè)字段來存儲(chǔ)傳送的數(shù)據(jù),通過Map來存放。
對(duì)于Action Type,我們可以通過一個(gè)接口或者類來進(jìn)行記錄,將所有的類型保存在其中。方便我們的調(diào)用。
public interface ShowActions {
String TODO_SHOW = "todo-show";
String GET_TEXT = "get-text";
}
如何創(chuàng)建Action,定義一個(gè)類,專門用來根據(jù)我們可能會(huì)出現(xiàn)的各種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);
}
在我們準(zhǔn)備用ActionsCreator來創(chuàng)建Action的時(shí)候,我們并沒有直接new Action這種方式來做,而是將其通過調(diào)度器,對(duì)其進(jìn)行了分發(fā)。這里的事件分發(fā),我們使用的是Otto的Bus來進(jìn)行事件的分發(fā)。
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);
}
}
在調(diào)度的過程中,我們將傳遞進(jìn)來的數(shù)據(jù)進(jìn)行一個(gè)解析,然后根據(jù)數(shù)據(jù)創(chuàng)建出相應(yīng)的Action,然后對(duì)Action進(jìn)行分發(fā),這個(gè)時(shí)候關(guān)注了相應(yīng)的Action的Store就會(huì)開始根據(jù)相應(yīng)的Action開始執(zhí)行相應(yīng)的操作。在Store中,聲明了一個(gè)抽象方法onAction來負(fù)責(zé)進(jìn)行對(duì)于Action的判斷和分發(fā),然后定義了StoreChangeEvent接口作為事件變化,當(dāng)有變化的時(shí)候,通過這個(gè)進(jìn)行傳遞,我們可以自己實(shí)現(xiàn)這個(gè)接口,然后在里面添加一些方法和字段用來攜帶數(shù)據(jù)。
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 {
}
}
然后我們?cè)?code>View也就是Activity中訂閱了變化時(shí)間的方法,這個(gè)時(shí)候就可以實(shí)現(xiàn)對(duì)于View中的數(shù)據(jù)的一個(gè)動(dòng)態(tài)更新。
@Subscribe
public void showText (ShowStore.ShowChangeEvent event){
mTextView.setText(mShowStore.getShowText());
}
總結(jié)
通過Flux架構(gòu),使用的流程是,我們的View的事件會(huì)攜帶數(shù)據(jù),通過一個(gè)ActionsCreate創(chuàng)建一個(gè)Type的Action,實(shí)際完成過程是在Dispatcher的dispatch中,然后再將這個(gè)Action丟給訂閱了該Action的Store方法中,在這里完成各種邏輯,處理,甚至是可以發(fā)起網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù),處理完成,可以將結(jié)果封裝成一個(gè)事件,然后這個(gè)事件會(huì)再次通過調(diào)度器中的emitChangeEvent將事件傳遞給訂閱了該事件的函數(shù),而這個(gè)接收響應(yīng)事件的函數(shù)被我們定義在我們View中,從而實(shí)現(xiàn)對(duì)于我們View的更新。以上就是本文的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家學(xué)習(xí)Flux架構(gòu)有所幫助。
- 六款值得推薦的android(安卓)開源框架簡(jiǎn)介
- Android Retrofit 2.0框架上傳圖片解決方案
- 簡(jiǎn)略分析Android的Retrofit應(yīng)用開發(fā)框架源碼
- 舉例講解Android應(yīng)用開發(fā)中OTTO框架的基本使用
- Android通用流行框架大全【整理】
- Android之使用Android-query框架開發(fā)實(shí)戰(zhàn)(二)
- Android中XUtils3框架使用方法詳解(一)
- Android AndBase框架使用封裝好的函數(shù)完成Http請(qǐng)求(三)
- Android最基本的異步網(wǎng)絡(luò)請(qǐng)求框架
相關(guān)文章
Android實(shí)現(xiàn)快遞物流跟蹤布局效果
本篇文章主要介紹了Android實(shí)現(xiàn)快遞跟蹤布局效果,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
開源電商app常用標(biāo)簽"hot"之第三方開源LabelView
這篇文章主要介紹了開源電商app常用標(biāo)簽"hot"之第三方開源LabelView,對(duì)開源電商app相關(guān)資料感興趣的朋友一起學(xué)習(xí)吧2015-12-12
Android中簡(jiǎn)單的電話管理與短信管理App編寫實(shí)例
這篇文章主要介紹了Android中簡(jiǎn)單的電話管理與短信管理App編寫實(shí)例,包括監(jiān)聽電話的呼叫狀態(tài)以及短信群發(fā)聯(lián)系人選擇等基本功能的實(shí)現(xiàn),代碼突出要點(diǎn),需要的朋友可以參考下2016-04-04
Android開發(fā)歡迎頁點(diǎn)擊跳過倒計(jì)時(shí)進(jìn)入主頁
沒點(diǎn)擊跳過自然進(jìn)入主頁,點(diǎn)擊跳過之后立即進(jìn)入主頁,這個(gè)功能怎么實(shí)現(xiàn)呢,本文通過實(shí)例代碼給大家介紹Android開發(fā)歡迎頁點(diǎn)擊跳過倒計(jì)時(shí)進(jìn)入主頁,感興趣的朋友一起看看吧2023-12-12
FFmpeg?Principle學(xué)習(xí)new_video_stream添加視頻輸出流
這篇文章主要為大家介紹了FFmpeg?Principle學(xué)習(xí)new_video_stream添加視頻輸出流示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Android實(shí)現(xiàn)圖片文字識(shí)別
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圖片文字識(shí)別,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
android開發(fā)環(huán)境中SDK文件夾下的所需內(nèi)容詳解
在本篇文章里小編給大家整理的是關(guān)于android開發(fā)環(huán)境中SDK文件夾下的所需內(nèi)容詳解,有興趣的朋友們參考學(xué)習(xí)下。2019-09-09
Android使用Notification實(shí)現(xiàn)寬視圖通知欄(二)
這篇文章主要為大家詳細(xì)介紹了Android使用Notification實(shí)現(xiàn)寬視圖通知欄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12

