前言: 青春不是一個年紀的終結,也不是面孔的日益乾癟,而是永遠有衝刺夢想的心情和挑戰的勇氣。
一、概述
EventBus是適用於Android和Java的發佈/訂閱事件總線。主要功能是替代Intent、Handler、BroadCast在Activity、Fragment、Service線程之間傳遞消息。EventBus能夠簡化應用組件間的通信,解耦(有效分離)事件的發送者和接收者,避免複雜和容易出錯的依賴和生命週期問題,開銷小,代碼更優雅。
Andorid組件間通信,可能都是用Handler消息機制或者廣播機制來實現通信,但是它們代碼量大,組件上容易產生耦合 。爲什麼選擇使用EventBus來做通信?
- 簡化了組件間間的通信;
- 對事件通信雙方進行解耦 ;
- 在Activity、Fragment和後臺線程中能很好使用;
- 避免了複雜且容易出錯的依賴性和生命週期問題 ;
- 可以靈活方便指定工作線程和優先級 ;
- 速度快,性能好,代碼簡單優雅;
- 庫比較小,不佔內存。
二、使用步驟
(1)定義事件對象
事件對象可以是任意java類型,沒有特殊要求,比如String、int、自定義類等。
public class MessageEvent {
public String name;
}
(2)在接收消息的頁面註冊事件
EventBus.getDefault().register(this);
● register(Object subscriber): EventBus訂閱事件的方法,通過EventBus.getDefault()
獲取事件總線實例;參數subscriber爲訂閱者,訂閱者有處理事件的方法,並且必須添加@Subscribe註解。
只有註冊了訂閱事件,纔會接收到消息。注意:通常根據Activity和Fragment的生命週期註冊和註銷事件。
(3)訂閱者實現事件處理方法
也稱爲"訂閱者方法",當發佈對應事件類型時,該方法被調用(在接收消息的頁面)。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent message){
//TODO 接收事件後Do something
}
● @Subscribe: 必須使用@Subscribe註解來定義訂閱者方法,否則事件處理方法無法生效。
● threadMode: 線程模式,表示在哪個線程裏面執行,ThreadMode.MAIN表示在主線程執行該方法。(其他模式在下一篇講解)
● onMessageEvent(MessageEvent message): 事件處理方法的方法名稱,onMessageEvent()
是任意的合法方法名,開發者可以自己定義;參數類型MessageEvent爲定義接收事件的對象類型,要與發佈事件的類型一致,否則無法接收事件。
(4)發佈事件
EventBus.getDefault().post(Object event);
● post(Object event): EventBus發送事件的方法,參數event爲事件對象,是Object任意類型,這裏發送的類型需要與接收事件的類型一致。
當前與事件類型匹配的所有已註冊的事件都會接收到。
(5)在接收消息的頁面註銷(解除註冊)事件
EventBus.getDefault().unregister(this);
● unregister(Object subscriber): 給訂閱者註銷事件的方法,如果事件不需要使用了必須調用該方法註銷事件。
當消息頁面不存在或者不需要事件了註銷該事件。
三、項目實戰
3.1 普通使用
我們首先來演示個例子,在OneActivity中註冊事件並實現事件處理方法,點擊按鈕跳轉到TwoActivity中,點擊TwoActivity的“發送事件”按鈕向OneActivity發送事件,OneActivity在接收到事件信息後吐司並將接收的數據顯示在屏幕上。
我們按照下面的步驟實現這個效果:
(1)使用EventBus需要在build.gradle文件中添加依賴:
添加EventBus3.2依賴:
implementation 'org.greenrobot:eventbus:3.2.0'
(2)定義事件對象
事件對象可以是任意java類型(Object),沒有特殊要求,比如String、int、自定義類等,開發者可以根據需求選擇。這裏我們定義一個類MessageEvent:
public class MessageEvent {
public MessageEvent(String name) {
this.name = name;
}
public String name;
}
這個類很簡單,只定義了一個參數name,構造時傳入一個字符串。它是用於我們發送事件的事件對象攜帶參數的封裝類,在下面訂閱者方法接收的參數中也是以MessageEvent爲接收類型才能接收到。兩個類型要一致才能成功接收到發出的數據。
(3)在接收消息的頁面註冊和註銷事件
從上面的效果可以看到在OneActivity中接收到事件消息,那麼我們需要在OneActivity註冊和註銷事件,通常根據Activity和Fragment的生命週期註冊和註銷事件。那麼我們在Activity的onCreate()
方法中註冊事件,在onDestroy()
方法中註銷事件:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
只有消息頁面存在並且註冊了訂閱事件,發佈的事件纔會接收到。當消息頁面不存在或者不需要事件了註銷該事件。
注意:如果消息頁面不存在或者頁面已經被銷燬了,發佈的事件是無法接收到的。所以發佈事件前需要明確接收消息的頁面已經創建並且註冊了事件。另外,粘性事件能實現先發布事件,後續再註冊事件,這樣也能接收事件,下面會講解。
(4)訂閱者實現事件處理的方法
需要在消息頁面OneActivity實現事件處理的方法,也稱爲"訂閱者方法",當發佈對應事件類型時,該方法被調用,接收到事件的消息。定義一個接收事件的方法onMessageEvent()
,將接收的數據設置到mTv_content控件中,並且吐司顯示。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent message) {
//TODO 接收事件後Do something
mTv_content.setText("onMessageEvent:" + message.name);
Toast.makeText(this, "onMessageEvent:" + message.name, Toast.LENGTH_SHORT).show();
}
必須使用@Subscribe()
註解來定義訂閱者方法,並且在裏面聲明threadMode線程模式,這裏爲在主線程ThreadMode.MAIN
中接收數據,方法名onMessageEvent()
是任意的合法方法名,開發者可以自己定義,參數類型MessageEvent爲定義事件的對象類型,要與發佈事件的類型一致,否則無法接收事件。
(5)發佈事件
發送事件是在TwoActivity中是實現的,通過EventBus中的Psot()
方法發佈事件,參數爲上面自定義的MessageEvent,可以將攜帶的數據寫入MessageEvent中,這裏對象的類型要與接收事件的類型一致。
EventBus.getDefault().post(new MessageEvent("接收到TwoActivity發送過來的事件啦"));
那麼整個過程就完成了,是不是很簡單,這裏貼出兩個Activity的代碼,其他代碼就不一一貼出來了,比較簡單。(源碼在文章最後給出)
接收消息頁面:OneActivity.java
/**
* 註冊並接收普通事件
*/
public class OneActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mTv_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
findViewById(R.id.btn_skip).setOnClickListener(this);
mTv_content = findViewById(R.id.tv_content);
//1.註冊事件
EventBus.getDefault().register(this);
}
//3.接收事件處理
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent message) {
//TODO 接收事件後Do something
mTv_content.setText("onMessageEvent:" + message.name);
Toast.makeText(this, "onMessageEvent:" + message.name, Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_skip://跳轉到TwoActivity
startActivity(new Intent(this, TwoActivity.class));
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//2.反註冊事件
EventBus.getDefault().unregister(this);
}
}
發送消息頁面:TwoActivity.java
/**
* 發佈普通事件
*/
public class TwoActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mTv_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
findViewById(R.id.btn_send).setOnClickListener(this);
mTv_content = findViewById(R.id.tv_content);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_send://發佈事件
mTv_content.setText("對OneActivity發佈事件");
//4.發佈普通事件
EventBus.getDefault().post(new MessageEvent("接收到TwoActivity發送過來的事件啦"));
break;
default:
break;
}
}
}
3.2 粘性事件的使用
上面的普通事件中,訂閱者(接收消息的頁面OneActivity)要先註冊,才能接收到發佈的事件;也就是說接收消息的頁面還沒創建或者未註冊訂閱者,那麼處理事件的方法根本無法接收發送者(發送消息頁面TwoActivity)發佈的事件。EventBus提供了一種粘性事件,能在發送事件之後再訂閱該事件也能接收到該事件。與普通事件不同,普通事件是先註冊後發佈,粘性事件可以先發布後註冊。
比如在項目中,在Activity1中發送事件到Activity2中做事件處理,如果Activity2沒創建,那麼是無法接收消息的,主要是Activity2用於接收消息的EventBus還沒完成註冊,即使發佈了事件,訂閱者還沒產生,所以沒法接收。
粘性事件的使用步驟和普通事件的使用步驟大致相同,不同的是發佈和處理事件的方法:
(1)粘性事件的事件函數處理方法,需要在註解中添加sticky = true
標識,表示該事件是粘性事件:
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onStickyEvent(MessageEvent message) {
//TODO 接收事件後Do something
}
(2)使用postSticky()
發佈粘性事件:
EventBus.getDefault().postSticky(Object event);
發佈粘性事件後,EventBus將會一直存在粘性事件,在不需要粘性事件的時候需要及時移除,移除的方法有下面幾個:
//移除指定的粘性事件
removeStickyEvent(Object event);
//移除指定對象類型的粘性事件
removeStickyEvent(Class<T> eventType);
//移除所有粘性事件
removeAllStickyEvents();
我們舉個例子,創建兩個Activity,在StickySendActivity中向StickyReceiveActivity發佈粘性事件,發佈完後跳轉到StickyReceiveActivity中,StickyReceiveActivity創建並註冊EventBus,訂閱粘性事件的處理方法:
/**
* 發佈粘性事件
*/
public class StickySendActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sticky_send);
findViewById(R.id.btn_send).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_send://發佈事件
//4.發佈粘性事件
EventBus.getDefault().postSticky("StickySendActivity發送粘性事件");
startActivity(new Intent(this, StickyReceiveActivity.class));
break;
}
}
}
點擊發送粘性事件按鈕向StickyReceiveActivity發佈粘性事件,發佈完後跳轉到StickyReceiveActivity中;
/**
* 註冊並接收粘性事件
*/
public class StickyReceiveActivity extends AppCompatActivity{
private TextView mTv_content;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sticky_receive);
mTv_content = findViewById(R.id.tv_content);
//1.註冊事件
EventBus.getDefault().register(this);
}
//3.接收StickySendActivity粘性事件處理, sticky = true表示是粘性事件
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onStickyEvent(String str) {
//TODO 接收事件後Do something
mTv_content.setText("onStickyEvent:接收到" + str);
Toast.makeText(this, "onStickyEvent:接收到" + str, Toast.LENGTH_SHORT).show();
EventBus.getDefault().removeStickyEvent(this)//移除粘性事件
}
@Override
protected void onDestroy() {
super.onDestroy();
//2.反註冊事件
EventBus.getDefault().unregister(this);
}
}
StickyReceiveActivity創建並註冊EventBus,訂閱粘性事件的處理方法,接收到粘性事件發送的數據,顯示在mTv_content控件上並吐司提示,然後通過removeStickyEvent(this)
移除當前的粘性事件。效果如下:
可以看到先發送粘性事件,後再註冊處理事件也能接收到事件。
注意:發送事件的參數類型一定要與接收事件的參數類型一致,否則無法接收到事件的。
至此,本文結束!有關EventBus深入理解和AndroidEventBus的使用在下一篇講解。
源碼地址:https://github.com/FollowExcellence/EventBusDemo
請尊重原創者版權,轉載請標明出處:https://blog.csdn.net/m0_37796683/article/details/105585228 謝謝!
相關文章:
EventBus3.2詳解和使用(一)
● EventBus:普通事件和粘性事件的使用
EventBus3.2詳解和使用(二)
● EventBus三要素、線程模式、優先級和AndroidEventBus的使用
EventBus3.2詳解和使用(三)
● EventBus內部原理