天天看點

android3.0版本,Android---EventBus3.0版本的使用及說明

EventBus3.0事件介紹

EventBus是一個基于觀察者模式,并且是針對了Android進行優化的釋出/訂閱的事件總線。簡化了應用程式内各元件間、元件與背景線程間的通信。優點是開銷小,代碼更優雅,以及将發送者和接收者解耦,避免了産生大量的内部類。

EventBus3.0應用的範圍比較廣,比如請求網絡,當請求網絡後,可以通過handler和broadcast通知UI,同樣也可以使用EventBus3.0實作。Activity和Activity進行互動還好說,如果Fragment和Fragment進行互動着實令人頭疼,我們會使用廣播來處理,但是使用廣播稍顯麻煩并且效率也不高,如果傳遞的資料是實體類需要序列化,那麼很顯然成本會有點高。

是以在涉及Activity與Fragment之間,Fragment與Fragment之間進行互動的時候,優先考慮使用EventBus3.0進行通信。關于EventBus3.0更多的介紹可以參考EventBus官方介紹:

EventBus3.0的三大要素

講述eventBus的工作流程,可以先看下官網給出的關系圖

android3.0版本,Android---EventBus3.0版本的使用及說明

官網提供的關系圖

事件的釋出者Publisher通過post事件,将具體的事件通知給事件的訂閱者Subscriber,然後在由訂閱者對接收到的事件進行處理。

Event:事件

可以是任意類型的資料,比如簡單的string類型的擷取;

public class updateTextEvent {

private static final String TAG = "AA";

private String msg;

public updateTextEvent(String msg) {

this.msg = msg;

Log.i(TAG, "updateTextEvent: " + msg);

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

}

Publisher:事件釋出者

可以在任意線程任意位置發送事件,直接調用EventBus的post(Object)方法。可以自己執行個體化EventBus對象,但一般使用EventBus.getDefault()就好了,根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。

Subsriber:事件訂閱者

在EventBus3.0之前的EventBus1.0和EventBus2.0時代消息處理的方法隻能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他們分别代表四種線程模型。而在EventBus3.0之後,事件處理的方法可以随便取名,但是需要添加一個注解@Subscribe,并且要指定線程模型(預設為POSTING)。例:

@Subscribe(threadMode = ThreadMode.MAIN)

public void modifyBtn4(updateTextEvent msg){

button.setText(msg.getMsg());

}

綜合上述的流程及對于其中重要的三個元素的認識,可以認為在使用EventBus3.0總共分為以下幾個步驟:

前提:

在Android studio的module的build.gradle中配置編譯庫連接配接:目前最新的版本為3.1.1

compile 'org.greenrobot:eventbus:3.1.1'

事件的定義

public static class MessageEvent {

}

事件訂閱者的準備

聲明并且采用注解的方式來定義訂閱者的方法,預設的情況下,注解方法中的threadMode為MAIN,表示在主線程中運作,事件處理的函數名可以自行定義。下面會講述4中線程的模式。

@Subscribe(threadMode = ThreadMode.MAIN)

public void onMessageEvent(MessageEvent event) {

};

事件的釋出者的準備

事件釋出者的工作相對比較簡單,最常用的是采用post或者postSticky的方法,将new出來的事件對象釋出出來,這兩種釋出的方法,将會在下面知識讨論中進行講述其差別。

EventBus.getDefault().post(new MessageEvent());

那麼問題來了,時間的訂閱者如何才能得知有事件被釋出了呢?是以在使用EventBus3.0的時候需要在事件訂閱的那個activity或者fragment中進行注冊,其注冊代碼的地方依附于activity或者fragment的生命周期,即:

@Override

public void onStart() {

super.onStart();

//在事件被訂閱的界面中注冊EventBus

EventBus.getDefault().register(this);

}

@Override

public void onStop() {

super.onStop();

//登出EventBus

EventBus.getDefault().unregister(this);

}

EventBus的四種線程模型---ThreadMode

在講述事件訂閱者的時候,采用添加注解的方法@Subscribe(threadMode = ThreadMode.MAIN)對事件的處理進行差別,檢視EventBus3.0線程模型文檔,有以下幾種線程模型,來幫助開發者針對不同的事件,和事件消費類型進行選擇。

ThreadMode: POSTING

預設的線程模式,如果使用事件處理函數指定了線程模型為POSTING,那麼該事件在哪個線程釋出出來的,事件處理函數就會在這個線程中運作,也就是說釋出事件和接收事件在同一個線程。此外,線上程模型為POSTING的事件處理函數中盡量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。

ThreadMode: MAIN

事件的處理會在UI線程中執行。此外也不能在處理事件中執行比較耗時的操作,否則也會引起ANR。

ThreadMode: BACKGROUND

如果事件是在UI線程中釋出出來的,那麼該事件處理函數就會在新的線程中運作,如果事件本來就是子線程中釋出出來的,那麼該事件處理函數直接在釋出事件的線程中執行。在此事件處理函數中禁止進行UI更新操作。

ThreadMode: ASYNC

無論事件在哪個線程釋出,該事件處理函數都會在建立的子線程中執行,同樣,此事件處理函數中禁止進行UI更新操作,因為這牽涉到UI的更新隻能在 main thread中更新。

在通過學習并了解了上面的EventBus3.0的相關知識後,可以進行一些資料的通信了。按照EventBus3.0的三大要素,分别進行操作實作資料的通信。

首先添加庫依賴

//ButterKnife控件綁定依賴

compile 'com.jakewharton:butterknife:8.8.1'

annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

//EventBus控件綁定

compile 'org.greenrobot:eventbus:3.1.1'

事件

public class updateTextEvent {

private static final String TAG = "AA";

private String msg;

public updateTextEvent(String msg) {

this.msg = msg;

Log.i(TAG, "updateTextEvent: " + msg);

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

}

事件的訂閱者及事件的訂閱者

public class MainActivity extends AppCompatActivity {

private static final String TAG = "AA";

@BindView(R.id.button1)

Button button1;

@BindView(R.id.button2)

Button button2;

@BindView(R.id.button3)

Button button3;

@BindView(R.id.button4)

Button btn4;

@BindView(R.id.button5)

Button button5;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//注冊ButterKnife

ButterKnife.bind(this);

//注冊EventBus

EventBus.getDefault().register(this);

}

//添加對于button 按鈕事件的注解

@OnClick({R.id.button1, R.id.button2, R.id.button3, R.id.button4, R.id.button5})

public void onViewClicked(View view) {

switch (view.getId()) {

case R.id.button1:

Toast.makeText(this,"開始",Toast.LENGTH_SHORT).show();

break;

case R.id.button2:

// EventBus.getDefault().postSticky(new updateTextEvent("這是一個測試"));

EventBus.getDefault().post(new updateTextEvent("這是一個測試"));

// Intent intent = new Intent(this,SecActivity.class);

// startActivity(intent);

break;

case R.id.button3:

break;

case R.id.button4:

break;

case R.id.button5:

break;

}

}

//更改button4的文本内容

@Subscribe(threadMode = ThreadMode.MAIN)

public void modifyBtn4(updateTextEvent msg){

// list.get(3).setText(msg.getMsg());

btn4.setText(msg.getMsg());

}

@Override

protected void onDestroy() {

super.onDestroy();

//登出EventBus

EventBus.getDefault().unregister(this);

}

}

細心的讀者應該也注意到了在上述MainActivity中,使用到了Jake Whaton大神的butterknife的使用。測試結果如下,可以正常的進行資料的通信。

android3.0版本,Android---EventBus3.0版本的使用及說明

Activity測試通信OK

按照上面的事件釋出及訂閱事件,在同一個activity中進行事件的通信是沒有問題的,那如果按下上述的button2,能否将這個事件釋出通知到其他activity中的訂閱者呢?建立一個SecActivity,代碼如下:

public class SecActivity extends AppCompatActivity {

@BindView(R.id.textview)

TextView text;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_sec);

ButterKnife.bind(this);

EventBus.getDefault().register(this);

}

@Subscribe(threadMode = ThreadMode.MAIN)

public void cha(updateTextEvent msg){

text.setText(msg.getMsg());

}

@Override

protected void onDestroy() {

super.onDestroy();

EventBus.getDefault().unregister(this);

}

}

同時在修改MainActivity中的代碼,注釋掉EventBus的注冊和登出代碼。

//EventBus.getDefault().register(this);

//EventBus.getDefault().unregister(this);

并且添加activity的跳轉代碼,當按下button2的時候,正常跳轉到SecActivity,但是并沒有預期的修改text的現象,查詢log如下,提示并沒有注冊訂閱者。

11-23 07:55:43.599 6286-6286/com.example.myapplication D/EventBus: No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent

--------- beginning of system

11-23 07:55:43.652 6286-6325/com.example.myapplication D/EGL_emulation: eglMakeCurrent: 0xaa7c7240: ver 2 0 (tinfo 0xaa7e00a0)

11-23 07:55:43.653 6286-6325/com.example.myapplication D/EGL_emulation: eglMakeCurrent: 0xaa7c7240: ver 2 0 (tinfo 0xaa7e00a0)

理清思路,事件的釋出和訂閱是與activity的生命周期有關系的,如何解決這個問題呢?還記得上面講述的postSticky()方法嗎?

查詢這個這個文檔:Sticky Events的官方文檔,意譯為:先釋出事件,然後在訂閱。

是以修改MainActivity中post代碼為:

EventBus.getDefault().postSticky(new updateTextEvent("這是一個測試"));

與此同時,也需要修改SecActivity的代碼:

public class SecActivity extends AppCompatActivity {

@BindView(R.id.textview)

TextView text;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_sec);

ButterKnife.bind(this);

EventBus.getDefault().register(this);

}

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)

public void cha(updateTextEvent msg){

text.setText(msg.getMsg());

}

@Override

protected void onDestroy() {

super.onDestroy();

EventBus.getDefault().unregister(this);

}

}

測試結果如下圖:

android3.0版本,Android---EventBus3.0版本的使用及說明

image.png

至此,EventBus3.0的常用方法及使用的說明,開發者應該有了基本的認識了。愉快的coding吧。

EventBus3.0的釋出及廣泛的應用已經有很長時間了,文中部分内容參考借鑒了其他開發者的部落格内容:

非常感謝簡書提供的這個知識彙聚分享的平台。