開源庫之EventBus使用詳解
簡介
EventBus是一種用於Android的釋出/訂閱事件匯流排。簡化了應用程式內各元件間、元件與後臺執行緒間的通訊。常用於Activity、Fragment和後臺Service之間通訊、傳遞資料。
API
作為一個訊息匯流排主要有三個組成部分:事件(Event)、事件訂閱者(Subscriber)、事件釋出者(Publisher)。
使用
- 在模組的 build.gradle 構建指令碼中新增EventBus依賴
dependencies {
...
implementation 'org.greenrobot:eventbus:3.1.1'
}
- 定義事件,事件可以是任意普通的Java物件,沒有任何特殊的要求
public class MessageEvent {
private String msg;
public MessageEvent(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
- 訂閱事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
// 註冊訂閱者
EventBus.getDefault().register(this);
}
// 事件處理方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMainEvent (MessageEvent event) {
Log.e(TAG, "onMainEvent方法接收的資料---->" + event.getMsg());
}
// 登出訂閱者
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
- 釋出事件, 在需要的地方釋出事件,所有訂閱了該型別事件並已註冊的訂閱者將收到該事件。
EventBus.getDefault().post(new MessageEvent("main"));
執行緒模式
使用執行緒模式來指定訂閱者方法的執行緒
ThreadMode.POSTING
訂閱者方法將在釋出事件所在的執行緒中被呼叫。這是預設的執行緒模式,事件的傳遞是同步的,一旦釋出事件,所有該模式的訂閱者方法都將被呼叫。這種執行緒模式意味著最少的效能開銷,因為它避免了執行緒的切換。因此,對於不要求是主執行緒並且耗時很短的簡單任務推薦使用該模式。使用該模式的訂閱者方法應該快速返回,以避免阻塞釋出事件的執行緒,這可能是主執行緒。
ThreadMode.MAIN
訂閱者方法將在主執行緒(UI執行緒)中被呼叫。因此,可以在該模式的訂閱者方法中直接更新UI介面。如果釋出事件的執行緒是主執行緒,那麼該模式的訂閱者方法將被直接呼叫。使用該模式的訂閱者方法必須快速返回,以避免阻塞主執行緒。
ThreadMode.MAIN_ORDERED
訂閱者方法將在主執行緒(UI執行緒)中被呼叫。因此,可以在該模式的訂閱者方法中直接更新UI介面。事件將先進入佇列然後才傳送給訂閱者,所以釋出事件的呼叫將立即返回。這使得事件的處理保持嚴格的序列順序。使用該模式的訂閱者方法必須快速返回,以避免阻塞主執行緒
ThreadMode.BACKGROUND
訂閱者方法將在後臺執行緒中被呼叫。如果釋出事件的執行緒不是主執行緒,那麼訂閱者方法將直接在該執行緒中被呼叫。如果釋出事件的執行緒是主執行緒,那麼將使用一個單獨的後臺執行緒,該執行緒將按順序傳送所有的事件。使用該模式的訂閱者方法應該快速返回,以避免阻塞後臺執行緒。
ThreadMode.ASYNC
訂閱者方法將在一個單獨的執行緒中被呼叫。因此,釋出事件的呼叫將立即返回。如果訂閱者方法的執行需要一些時間,例如網路訪問,那麼就應該使用該模式。避免觸發大量的長時間執行的訂閱者方法,以限制併發執行緒的數量。EventBus使用了一個執行緒池來有效地重用已經完成呼叫訂閱者方法的執行緒。
具體示例
- ThreadMode.POSTING
// 在EventBusActivity 中進行註冊訂閱、處理訂閱者方法、登出訂閱
public class EventBusActivity extends AppCompatActivity {
private static final String TAG = EventBusActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
// 註冊訂閱者
EventBus.getDefault().register(this);
}
// 事件處理方法
@Subscribe(threadMode = ThreadMode.POSTING)
public void onPostingEvent(MessageEvent event) {
Log.e(TAG, "onPostingEvent方法接收的資料---->" + event.getMsg()+ "---所線上程---->" + Thread.currentThread().getName());
}
// 登出訂閱者
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
// 在EventSecondActivity 進行傳送事件
public class EventSecondActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = EventSecondActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_second);
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn:
// 在main 主執行緒呼叫
EventBus.getDefault().post(new MessageEvent("posting"));
break;
}
}
}
結果:
- ThreadMode.MAIN
// EventBusActivity 程式碼
......
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMainEvent(MessageEvent event) {
Log.e(TAG, "onMainEvent方法接收的資料---->" + event.getMsg() + "---所線上程---->" + Thread.currentThread().getName());
}
.......
// EventSecondActivity 進行傳送事件
.......
EventBus.getDefault().post(new MessageEvent("main"));
- ThreadMode.BACKGROUND
// EventBusActivity 程式碼
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onBackgroundEvent(MessageEvent event) {
Log.e(TAG, "onBackgroundEvent方法接收的資料---->" + event.getMsg() + "---所線上程---->" + Thread.currentThread().getName());
}
// EventSecondActivity 進行傳送事件
new Thread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new MessageEvent("background"));
Log.e(TAG, "---所線上程為--->" + Thread.currentThread().getName());
}
}).start();
結果:
- ThreadMode.ASYNC
// EventBusActivity 程式碼
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onAsyncEvent(MessageEvent event) {
Log.e(TAG, "onAsyncEvent 方法接收的資料---->" + event.getMsg() + "---所線上程---->" + Thread.currentThread().getName());
}
// EventSecondActivity 進行傳送事件
EventBus.getDefault().post(new MessageEvent("async"));
結果:
事件優先順序
EventBus支援在定義訂閱者方法時指定事件傳遞的優先順序。預設情況下,訂閱者方法的事件傳遞優先順序為0。數值越大,優先順序越高。在相同的執行緒模式下,更高優先順序的訂閱者方法將優先接收到事件
// EventBusActivity 程式碼
@Subscribe(threadMode = ThreadMode.MAIN, priority = 1)
public void onMainEvent(MessageEvent event) {
Log.e(TAG, "onMainEvent方法接收的資料---->" + event.getMsg() + "---所線上程---->" + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MAIN, priority = 2)
public void onMainEvent_2(MessageEvent event) {
Log.e(TAG, "onMainEvent_2方法接收的資料---->" + event.getMsg() + "---所線上程---->" + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MAIN, priority = 3)
public void onMainEvent_3(MessageEvent event) {
Log.e(TAG, "onMainEvent_3方法接收的資料---->" + event.getMsg() + "---所線上程---->" + Thread.currentThread().getName());
}
注意:優先順序只有在相同的執行緒模式下才有效。 結果:
粘性事件
如果先發布了事件,然後有訂閱者訂閱了該事件,那麼除非再次釋出該事件,否則訂閱者將永遠接收不到該事件。此時,可以使用粘性事件。釋出一個粘性事件之後,EventBus將在記憶體中快取該粘性事件。當有訂閱者訂閱了該粘性事件,訂閱者將接收到該事件
示例:
// EventBusActivity 程式碼
TextView tv_sticky = findViewById(R.id.tv_sticky);
tv_sticky.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EventBus.getDefault().postSticky(new MessageEvent("sticky"));
}
});
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(EventBusActivity.this, EventSecondActivity.class);
startActivity(intent);
}
});
// EventSecondActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_second);
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onStickyEvent(MessageEvent event) {
Log.e(TAG,"onStickyEvent 粘性事件接收---------->"+event.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
結果:
相關API:
- removeStickyEvent(Object event) 移除指定的粘性事件
- removeStickyEvent(Class eventType); 移除指定型別的粘性事件
- removeAllStickyEvents(); 移除所有的粘性事件
EventBus 外掛
專案使用EventBus ,裡面各種事件亂竄,這個外掛對於專案中事件橫飛的情況,還是非常好用的
- 在AndroidStudio Setting——–>Plugins
- 點選post事件小圖示,會直接列出所有接收的地方
- 點選接收事件的圖示,會直接列出所有傳送事件的地方: