事件總線模式是一種廣泛運用於安卓開發之中的一種軟件架構模式,而事件總線模式在安卓開發中最廣泛的應用莫過於AndroidStudio提供的EventBus,所以我就EventBus來談談對事件總線模式的認識。
EventBus是Android下高效的發布/訂閱事件總線機制。作用是可以代替傳統的Intent,Handler,Broadcast或接口函數在Fragment,Activity,Service,線程之間傳遞數據,執行方法。特點是代碼簡潔,是一種發布訂閱設計模式(Publish/Subsribe),或稱作觀察者設計模式。我們可能對事物總線機制還是有點陌生,但是想必對23種軟件設計模式之后的觀察者模式應該很熟悉。事物總線模式就是觀察者設計模式的一種,它的工作部件主要分為四種:事件源、事件監聽器、通道和事件總線。它的主要工作原理:事件源將產生的消息發送到事件總線的特定通道之上,然后監聽器在事先會訂閱事務總線之中不同的通道以區分消息的響應,然后當消息被發送到事務總線的特定通道之中時,所對應的監聽器會監聽到消息,然后監聽器根據程序中設置的響應函數進行執行。就好像一個Activity之中設置的Button一樣,在xml文件中放入一個Button,然后在java類中設定OnEvent()函數,當Button被點擊的時候,則會傳出一個點擊消息,然后按鈕對應的Onclick()函數,監聽到點擊消息,從而執行OnListerner()之中的函數。
那么下面我們結合具體的實例來分析事件總線模式,提到這個模式我們第一個想到的一定是Adroid開發之中的一個組件——Event Bus。Event Bus是Android Studio官方為我們提供的一個工具包。下面我們就根據一個具體的框架來對Event Bus進行講解。
我們想要實現的一個效果是,有兩個acivity如圖MainActivity:當點擊"click"按鈕的時候,就會跳轉到secondActivity,而secondActivity里面有兩個按鈕,點擊以后,可以改變MainActivity里面TextView的文字。
要實現這樣的效果無非是完成一個消息的傳遞,相當於我們的觀察者模式中發布者發布的一個消息,然后訂閱者通過特定的通道進行監聽,最后實現消息的傳遞。
首先是MainActivity:
public class MainActivity extends FragmentActivity { Button btn; TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getInstance().register(this); btn = (Button) findViewById(R.id.btn); text = (TextView) findViewById(R.id.text); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this,SecondActivity.class)); } }); } public void onEvent(Info i){ Log.i("cky", i.msg); } public void onEventMain(Info i){ text.setText(i.msg); } public void onEventMain(Info2 i){ text.setText(text.getText()+i.msg); } }
從上面我們可以看出MainActivity的創建函數onCreate函數中調用了EventBus的register(this)函數,用來注冊。然后是onEvent(),這個方法里面的代碼,會在一個子線程中執行一個是onEventMain(),這個方法里面的代碼,會在UI線程執行。
然后是SecondActivity
public class SecondActivity extends Activity { Button btn2; Button btn3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); btn2 = (Button) findViewById(R.id.btn2); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getInstance().post(new Info("信息1")); } }); btn3 = (Button) findViewById(R.id.btn3); btn3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getInstance().post(new Info2("信息2")); } }); } }
那么這些活動之中的“始作俑者”——EventBus類又是什么樣的呢?
public class EventBus { HashMap<Class<?>,ArrayList<Subscription>> subscriptionsByEventType = new HashMap<Class<?>,ArrayList<Subscription>>(); MainThreadHandler mainThreadHandler = new MainThreadHandler(this,Looper.getMainLooper()); AsyThreadHandler asyThreadHandler = new AsyThreadHandler(this); private final static EventBus instance = new EventBus(); public static EventBus getInstance(){ return instance; } private EventBus(){}; }
在這其中:
register方法之中我們先獲取了訂閱者(例子中是MainActivity)的方法,找到onEvent開頭的方法,獲得它們的參數類型。然后判斷subscriptionsByEventType是否有以這些參數類型為key的數據,如果沒有,新建一個ArrayList<Subscription>。
Subscription它代表一個訂閱,擁有subsriber,也就是訂閱者還有一個SubscriberMethod,這是訂閱方法類。
post()方法里面,如同我們上面所說,獲取了參數類型,然后在subscriptionsByEventType中查詢所有改類型對應的訂閱Subscription對於Subscription,它有我們訂閱類的所有信息。首先根據type判斷是在主線程還是子線程執行,然后調用一開始講到的兩個類的實例就好了。
invoke()其實只有一句話,就是調用了反射去執行方法。m是訂閱方法,sub.subscriber就是訂閱者,event就是post()方法傳入的實體這樣我們就在子線程中調用了這個方法了,相當於MainActivity主動調用這個方法。
這便是事件總線模式的實例講解,通過這個事例我們可以更加清晰地認識事件總線模式的結構和使用方法。