EventBus 消息處理框架

轉自:http://www.jianshu.com/p/a040955194fc

僅供學習使用

概述

EventBus是一個Android事件發佈/訂閱框架,通過解耦發佈者和訂閱者簡化Android事件傳遞,這裏的事件可以理解爲消息。事件傳遞既可以用於Android四大組件間通訊,也可以用於異步線程和主線程間通訊等。
傳統的事件傳遞方式包括:Handler、BroadcastReceiver、Interface回調,相比之下EventBus的有點是代碼簡潔,使用簡單,並將事件發佈和 訂閱充分解耦。

概念

事件Event: 又可成爲消息,其實就是一個對象,可以是網絡請求返回的字符串,也可以是某個開關狀態等等。事件類型EventType是指事件所屬的Class。

事件分爲一般事件和Sticky事件,相對於一般事件,Sticky事件不同之處在於,當事件發佈後,再有訂閱者開始訂閱該類型事件,依然能收到該類型事件的最近一個Sticky事件。

訂閱者Subscriber: 訂閱某種事件類型的對象,當有發佈者發佈這類事件後,EventBus會執行訂閱者的onEvent函數,這個函數叫事件響應函數。訂閱者通過register接口訂閱某個事件類型,unregister接口退訂。訂閱者存在優先級,優先級高的訂閱者可以取消事件繼續向優先級低的訂閱者分發,默認所有訂閱者優先級都爲0。

發佈者Publisher: 發佈某事件的對象,通過post接口發佈事件。

GitHub地址

EventBus源碼:https://github.com/greenrobot/EventBus

基本使用

自定義一個事件類

public class AnyEventType {
     public AnyEventType(){}
 }

在要接受消息的頁面註冊

EventBus.getDefault().register(this);

接收消息的方法

@Subscribe
public void onEvent(AnyEventType event) {/* Do something */};

發送消息

EventBus.getDefault().post(event);

取消註冊

EventBus.getDefault().unregister(this);

實例

下面我們來實現一個具體的例子來介紹EventBus的基本使用。

需求如下:在MainActivity中註冊EventBus事件,並實現事件響應方法,當點擊MainActivity中的按鈕時跳轉到SecondActivity,當點擊SecondActivity中的按鈕時向MainActivity發送Event事件,當MainActivity收到事件後,將事件內容顯示在TextView中。

  1. MainActivity


    MainActivity
  2. SecondActivity


  3. 事件處理


事件類Event

public class Event {

    private String messgae;

    public Event(String messgae) {
        this.messgae = messgae;
    }

    public String getMessgae() {
        return messgae;
    }
}

MainActivity

在OnCreate()函數中註冊EventBus,在Ondestroy()函數中反註冊。

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.btn_open)
    Button mOpenBtn;

    @Bind(R.id.tv_showinfo)
    TextView mInfoTxt;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);
        //註冊
        EventBus.getDefault().register(this);

    }

    /**
     * 事件響應方法
     * 接收消息
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(Event event) {

        String msg = event.getMessgae();
        mInfoTxt.setText(msg);
    }

    //綁定點擊事件
    @OnClick(R.id.btn_open)
    public void openSecondActivity(View view) {
            Intent intent = new Intent(MainActivity.this, SecondActivity.class);
            startActivity(intent);

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //反註冊
        EventBus.getDefault().unregister(this);
    }
}

SecondActivity

public class SecondActivity extends AppCompatActivity {

    @Bind(R.id.btn_post)
    Button mPostBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        ButterKnife.bind(this);


        mPostBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //發送事件
                        EventBus.getDefault().post(new Event("Just do it"));
                    }
                }).start();

            }
        });
    }

}

EventBus的事件訂閱函數

類別

在上面的例子中,我們再註解@Subscribe(threadMode = ThreadMode.MAIN)中使用了ThreadMode.MAIN這個模式,表示該函數在主線程即UI線程中執行,實際上EventBus總共有四種線程模式,分別是:

  • ThreadMode.MAIN:表示無論事件是在哪個線程發佈出來的,該事件訂閱方法onEvent都會在UI線程中執行,這個在Android中是非常有用的,因爲在Android中只能在UI線程中更新UI,所有在此模式下的方法是不能執行耗時操作的。

  • ThreadMode.POSTING:表示事件在哪個線程中發佈出來的,事件訂閱函數onEvent就會在這個線程中運行,也就是說發佈事件和接收事件在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。

  • ThreadMode.BACKGROUND:表示如果事件在UI線程中發佈出來的,那麼訂閱函數onEvent就會在子線程中運行,如果事件本來就是在子線程中發佈出來的,那麼訂閱函數直接在該子線程中執行。

  • ThreadMode.AYSNC:使用這個模式的訂閱函數,那麼無論事件在哪個線程發佈,都會創建新的子線程來執行訂閱函數。

實戰

如何調用不同的訂閱函數

要調用四種不同模式的訂閱函數,我們首先要用清楚EventBus是如何指定調用的函數的?

先回顧一下上一節中的例子是如何調用訂閱函數onEvent的,首先新建一個事件類:

public class Event {

    private String messgae;

    public Event(String messgae) {
        this.messgae = messgae;
    }

    public String getMessgae() {
        return messgae;
    }
}

發佈事件:

EventBus.getDefault().post(new Event("Just do it"));

訂閱事件:

    /**
     * 事件響應方法
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMain(Event event) {

        String msg = event.getMessgae();
        mInfoTxt.setText(msg);
    }

觀察可以發現:發佈事件中的參數是Event的實例,而訂閱函數中的參數也是Event的實例,可以推斷EventBus是通過post函數傳進去的類的實例來確定調用哪個訂閱函數的,是哪個就調用哪個,如果有多個訂閱函數呢,那麼這些函數都會被調用!

示例

下面我們來驗證這個推斷:

我們在基本使用章節的例子上進行擴展,首先建立四個類:FirstEvent、SecondEvent、ThirdEvent、FourthEvent。

FirstEvent.java

public class FirstEvent {

    private String messgae;

    public FirstEvent(String messgae) {
        this.messgae = messgae;
    }

    public String getMessgae() {
        return messgae;
    }
}

SecondEvent.java

public class SecondEvent {

    private String messgae;

    public SecondEvent(String messgae) {
        this.messgae = messgae;
    }

    public String getMessgae() {
        return messgae;
    }
}

ThirdEvent.java

public class ThirdEvent {

    private String messgae;

    public ThirdEvent(String messgae) {
        this.messgae = messgae;
    }

    public String getMessgae() {
        return messgae;
    }
}

FourthEvent.java

public class FourthEvent {

    private String messgae;

    public FourthEvent(String messgae) {
        this.messgae = messgae;
    }

    public String getMessgae() {
        return messgae;
    }
}

然後在MainActivity中,增加四種模式的訂閱函數

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Bind(R.id.btn_open)
    Button mOpenBtn;

    @Bind(R.id.tv_showinfo)
    TextView mInfoTxt;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);
        //註冊
        EventBus.getDefault().register(this);

    }

    /**
     * 事件響應方法
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMain(FirstEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventMain: " + event.getMessgae());
    }

    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onEventPosting(SecondEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventPosting: "+ event.getMessgae());
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onEventBackgroud(ThirdEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventBackgroud: " + event.getMessgae());
    }

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onEventAsync(FourthEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventAsync: " + event.getMessgae());
    }

    //綁定點擊事件
    @OnClick(R.id.btn_open)
    public void openSecondActivity(View view) {
            Intent intent = new Intent(MainActivity.this, SecondActivity.class);
            startActivity(intent);

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //反註冊
        EventBus.getDefault().unregister(this);
    }
}

接下來在SecondActivity中增加四個按鈕,分別發送不同類別的事件

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        ButterKnife.bind(this);
    }

    @OnClick(R.id.btn_post)
    public void onPostA() {
        EventBus.getDefault().post(new FirstEvent("FirstEvent"));
    }

    @OnClick(R.id.btn_post2)
    public void onPostB() {

        EventBus.getDefault().post(new SecondEvent("SecondEvent"));
    }

    @OnClick(R.id.btn_post3)
    public void onPostC() {

        EventBus.getDefault().post(new ThirdEvent("ThirdEvent"));
    }

    @OnClick(R.id.btn_post4)
    public void onPostD() {

        EventBus.getDefault().post(new FourthEvent("FourthEvent"));
    }
}

運行後,分別順序點擊SecondActivity的四個按鈕,打印信息如下:

03-31 02:53:45.950 4779-4779/com.example.michael.eventbusdemo I/MainActivity: onEventMain: FirstEvent
03-31 02:53:47.528 4779-4779/com.example.michael.eventbusdemo I/MainActivity: onEventPosting: SecondEvent
03-31 02:53:48.882 4779-4940/com.example.michael.eventbusdemo I/MainActivity: onEventBackgroud: ThirdEvent
03-31 02:53:50.462 4779-4940/com.example.michael.eventbusdemo I/MainActivity: onEventAsync: FourthEvent

由此可見,通過發佈不同的事件類的實例,EventBus根據類的實例分別調用了不同的訂閱函數來處理事件。

那麼,當同一個類的實例有多個函數訂閱時,結果會是怎樣呢?答案是,這些函數都會執行。下面我們來驗證一下,將MainActivity中訂閱函數的參數都改爲FirstEvent,代碼如下:

   /**
     * 事件響應方法
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMain(FirstEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventMain: " + event.getMessgae());
    }

    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onEventPosting(FirstEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventPosting: "+ event.getMessgae());
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onEventBackgroud(FirstEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventBackgroud: " + event.getMessgae());
    }

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onEventAsync(FirstEvent event) {

        String msg = event.getMessgae();
        Log.i(TAG, "onEventAsync: " + event.getMessgae());
    }

運行程序,點擊SecondActivity的FirstEvent按鈕,打印信息如下:

03-31 03:14:07.032 23611-23746/com.example.michael.eventbusdemo I/MainActivity: onEventAsync: FirstEvent
03-31 03:14:07.033 23611-23611/com.example.michael.eventbusdemo I/MainActivity: onEventMain: FirstEvent
03-31 03:14:07.033 23611-23611/com.example.michael.eventbusdemo I/MainActivity: onEventPosting: FirstEvent
03-31 03:14:07.034 23611-23748/com.example.michael.eventbusdemo I/MainActivity: onEventBackgroud: FirstEvent

分析可知,當SecondActivity發送FirstEvent事件過來的時候,這個四個訂閱函數會同時接收到這個事件並執行。

總結: 訂閱函數的執行是根據參數中的事件類的類名來決定的。



發佈了4 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章