EventBus3.2詳解和使用(一)

前言: 青春不是一個年紀的終結,也不是面孔的日益乾癟,而是永遠有衝刺夢想的心情和挑戰的勇氣。

一、概述

  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內部原理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章