EventBus是一個通過發佈、訂閱事件實現組件間消息傳遞的工具。 它存在的目的,就是為了優化組件之間傳遞消息的過程。傳統組件之間傳遞消息的方法有使用廣播,回調等,而這些方法使用都比較複雜。 工作原理: 依賴: 註:EventBus是事件-訂閱模型,實際上事件就是消息,訂閱就是接收,本文不會很嚴格區 ...
EventBus是一個通過發佈、訂閱事件實現組件間消息傳遞的工具。
它存在的目的,就是為了優化組件之間傳遞消息的過程。傳統組件之間傳遞消息的方法有使用廣播,回調等,而這些方法使用都比較複雜。
工作原理:
依賴:
1 dependencies { 2 compile 'org.greenrobot:eventbus:3.0.0' 3 }
註:EventBus是事件-訂閱模型,實際上事件就是消息,訂閱就是接收,本文不會很嚴格區分,方便理解為主!
1. 從簡單的入手:充當Handler
既然能發送消息,那麼自然在同一個組件下也能進行消息的發送和接收,也就是Handler的職責。
先定義一個事件的對象:
1 public class MessageEvent { 2 private String message; 3 4 public MessageEvent(String message) { 5 this.message = message; 6 } 7 8 public String getMessage() { 9 return message; 10 } 11 12 @Override 13 public String toString() { 14 return message; 15 } 16 }
這個事件對象只需要是Object的子類,沒其他要求,消息的內容可以隨意定,這裡用一個String表示事件的消息,toString直接輸出事件的內容。
在需要接收消息的組件中,進行EventBus的綁定,這裡由Activity充當訂閱者(Subscriber),也就是消息接收者。
1 public class MainActivity extends AppCompatActivity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 } 8 9 @Override 10 protected void onStart() { 11 super.onStart(); 12 EventBus.getDefault().register(this); // 將當前Activity綁定為訂閱者 13 } 14 15 @Override 16 protected void onStop() { 17 EventBus.getDefault().unregister(this); // 解綁 18 super.onStop(); 19 } 20 21 // 聲明一個訂閱方法,用於接收事件 22 @Subscribe 23 public void onEvent(MessageEvent messageEvent) { 24 Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]"); 25 } 26 27 }
通過EventBus.getDefault方法獲取到一個EventBus的一個單例,也就是每次調用這個方法得到的都是同一個EventBus對象。而不同的EventBus對象消息不會互通。
接著需要在Activity的onStart方法中進行對EventBus對象的綁定,在onStop方法中進行解綁。同時,需要定義用於接收事件的方法,並加上@Subscribe註解表明該方法用於接收訂閱事件。
接著,我們需要發送事件:
1 EventBus.getDefault().post(new MessageEvent("I m Fndroid"));
這裡獲取的預設的EventBus對象,通過post方法進行事件的發送,log如下:
2. 組件間通訊:代替廣播、回調等
EventBus的存在,並不是為了替代Handler,而是用來進行組件間的通訊。有了上面的知識,接下來就不難了。
我們都知道,只要是同一個EventBus對象綁定的組件(Subscriber),消息是互通的,也就是我們可以在Service中向Activity發送事件進行通訊。(其他組件類似)
定義一個IntentService,並且發送一個事件,而Activity,和上面一樣。
1 public class MyIntentService extends IntentService { 2 3 public MyIntentService() { 4 super("MyIntentService"); 5 } 6 7 @Override 8 protected void onHandleIntent(Intent intent) { 9 EventBus.getDefault().post(new MessageEvent("From service")); 10 } 11 12 }
在Activity中開啟服務:
1 startService(new Intent(this, MyIntentService.class));
Log:
組件間的通訊變得如此簡單了。
3. 進階:持久事件、線程模式、優先順序
① 持久事件(StickyEvent):對於調用post方法發送的普通消息,會在第一次被接收到的時候被消費掉,也就是我們在@Subscribe方法下處理完了,這個消息就消失了。而EventBus則提供了另一種類型的消息——StickyEvent,這個消息,會被保存在RAM中,直到下一個StickyEvent被髮送才會被替換。每個EventBus對象都能通過geStickyEvent方法獲取最近發出的持久事件。
我們對Activity稍作修改,在訂閱方法中,把當前的持久消息列印出來:
1 // 聲明一個訂閱方法,用於接收事件 2 @Subscribe 3 public void onEvent(MessageEvent messageEvent) { 4 Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]"); 5 Log.d(TAG, "onEvent: Sticky Event = [" + EventBus.getDefault().getStickyEvent(MessageEvent.class) + "]"); 6 }
接著對Service也進行修改,令其發送一個StickyEvent:
1 @Override 2 protected void onHandleIntent(Intent intent) { 3 EventBus.getDefault().post(new MessageEvent("From service")); 4 EventBus.getDefault().postSticky(new MessageEvent("From service2")); 5 EventBus.getDefault().post(new MessageEvent("From service3")); 6 }
這裡看到,在第二次發送的時候,調用了postSticky方法發送事件,這就表明瞭該事件是一個持久事件,除非有新的同類型(不同類型的事件可以共存)持久事件被髮送,否則會一直被保存在記憶體中,我們任何時候都能獲取得到。
Log:
可以看到,在第三次接收到消息的時候,將StickyEvent列印出來,依舊是"From service2"。
同樣的,如果我們想要移除此持久事件,可以調用EventBus的removeStickyEvent方法來實現,如果要移除所有類型的持久事件,可以調用removeAllStickyEvent方法。
② 線程模式
EventBus允許我們對訂閱者進行線程設置,預設情況下,訂閱是和事件發送處於同一線程的,我們不妨把訂閱的線程id列印出來看一看。
修改Activity中的@Subscribe方法:
1 @Subscribe 2 public void onEvent(MessageEvent messageEvent) { 3 Log.d(TAG, "onEvent: Thread id = [" + Thread.currentThread().getId() + "]"); 4 Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]"); 5 }
修改Service,讓其發送一次普通事件,並且輸出當前線程id:
1 @Override 2 protected void onHandleIntent(Intent intent) { 3 Log.d(TAG, "onHandleIntent: Thread id = [" + Thread.currentThread().getId() + "]"); 4 EventBus.getDefault().post(new MessageEvent("From service")); 5 }
列印Log:
對於訂閱者,有以下四種線程模式:
- POSTING:預設模式,訂閱和事件發送在同一線程下進行
- MAIN:訂閱在主線程下進行,可以直接修改UI
- BACKGROUND:如果事件發送在主線程,則訂閱在子線程下進行,如果事件發送在子線程,則訂閱也在該子線程中進行
- ASYNC:如果事件發送在主線程,則訂閱在子線程下進行,如果事件發送在子線程,則訂閱會在其他子線程中進行
設置訂閱者線程很簡單,只需要在註解中賦值即可,如:
1 @Subscribe(threadMode = ThreadMode.MAIN)
③ 優先順序
每個組件中可以有多個訂閱方法,而我們可以對它們設置不同的優先順序,設置的方法也很簡單:
1 @Subscribe(priority = 88)
預設的優先順序為0,更高優先順序的訂閱方法會更先收到事件,而每個訂閱方法都可以對事件進行終止,可以通過以下方法停止事件傳遞:
1 EventBus.getDefault().cancelEventDelivery(messageEvent);
④ 自定義EventBus對象
通過getDefault方法獲取的是一個EventBus預設的單例,而我們可以通過EventBus.Builder來構造一個自定義的EventBus對象。
明白了用法以後,我們分析源碼也會更加簡單。