1. 程式人生 > >EventBus詳解

EventBus詳解

1.前言

EventBus是一款針對Android優化的釋出/訂閱事件匯流排。可以替代廣播、startActivityForResult、Handler、非同步回撥等來實現各元件間、元件與後臺執行緒間的通訊。它的優點是開銷小,程式碼更優雅,以及將傳送者和接收者解耦。

通常我們在使用EventBus的時候都是直接需要接收通訊的Activity/Fragment中通過EventBus.getDefault().register(this)訂閱事件,在需要發起通訊的邏輯直接呼叫EventBus.getDefault().post(Object event)來發布事件。但是要是一個專案中有很多地方都使用EventBus來通訊,比如重新登入後更新各個頁面的登入狀態,或者是接收到通知更新訊息提示等,都這樣直接使用的話程式碼重複率很高,並且呢,如果以後升級或者更換EventBus時,各個地方都要修改,這就比較麻煩了。因此我一般是將EventBus的釋出和訂閱封裝到BaseActivity/BaseFragment中。

gitHub地址

2.概述

2.1新增依賴

implementation 'org.greenrobot:eventbus:3.1.1'

2.2三要素

  • Event 事件。它可以是任意型別。
  • Subscriber 事件訂閱者。在EventBus3.0之前我們必須定義以onEvent開頭的那幾個方法,分別是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之後事件處理的方法名可以隨意取,不過需要加上註解@subscribe(),並且指定執行緒模型,預設是POSTING。
  • Publisher 事件的釋出者。我們可以在任意執行緒裡釋出事件,一般情況下,使用EventBus.getDefault()就可以得到一個EventBus物件,然後再呼叫post(Object)方法即可。

2.3 四種執行緒模型

EventBus3.0有四種執行緒模型,分別是:

  • POSTING (預設) 表示事件處理函式的執行緒跟釋出事件的執行緒在同一個執行緒。
  • MAIN 表示事件處理函式的執行緒在主執行緒(UI)執行緒,因此在這裡不能進行耗時操作。
  • BACKGROUND 表示事件處理函式的執行緒在後臺執行緒,因此不能進行UI操作。如果釋出事件的執行緒是主執行緒(UI執行緒),那麼事件處理函式將會開啟一個後臺執行緒,如果果釋出事件的執行緒是在後臺執行緒,那麼事件處理函式就使用該執行緒。
  • ASYNC 表示無論事件釋出的執行緒是哪一個,事件處理函式始終會新建一個子執行緒執行,同樣不能進行UI操作。

3.基本實用

3.1定義事件

public class EventMessage<T> {
    private int code;//訊息型別
    private T data;//訊息資料

    public EventMessage(int code,T data){
        this.code=code;
        this.data=data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "EventMessage{" +
                "code=" + code +
                ", data=" + data +
                '}';
    }
}

 

3.2註冊事件

@Override
protected void onCreate(Bundle savedInstanceState) {           
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     EventBus.getDefault().register(this);
}

 

 

3.2解除註冊

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

 

3.3傳送事件

//普通事件
EventBus.getDefault().post(event);

//粘性事件
EventBus.getDefault().postSticky(event);

 

3.4處理事件

//普通事件處理
@Subscribe(threadMode = ThreadMode.MAIN)
public void onReceiveEvent(EventMessage msg){
//處理事件
}

//粘性事件處理
@Subscribe(threadMode = ThreadMode.MAIN,sticky=true)
public void onReceiveStickyEvent(EventMessage msg){
//事件處理
}
 

4.封裝

事件EventMessage:

public class EventMessage<T> {
    private int code;//訊息型別
    private T data;//訊息資料

    public EventMessage(int code,T data){
        this.code=code;
        this.data=data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "EventMessage{" +
                "code=" + code +
                ", data=" + data +
                '}';
    }
}

 

事件型別:EventCode:

/**
 * 訊息型別
 */
public class EventCode {
    //根據具體業務定義型別
    public static final int EVENT_A=1000;
    public static final int EVENT_B=1001;
    public static final int EVENT_C=1002;
    public static final int EVENT_D=1003;
    public static final int EVENT_E=1004;
}

 

EventBus封裝:

public class EventBusUtils {
    private EventBusUtils(){

    }

    /**
     * 註冊EventBus
     * @param subscribver
     */
    public static void register(Object subscribver){
        EventBus eventBus=EventBus.getDefault();
        if(!eventBus.isRegistered(subscribver)){
            eventBus.register(subscribver);
        }
    }


    /**
     * 解除註冊EventBus
     * @param subscriber
     */
    public static void unregister(Object subscriber){
        EventBus eventBus=EventBus.getDefault();
        if(eventBus.isRegistered(subscriber)){
            eventBus.unregister(subscriber);
        }
    }

    /**
     * 傳送普通事件訊息
     */
    public static void post(Object event){
        EventBus.getDefault().post(event);
    }

    /**
     * 傳送粘性事件訊息
     */
    public static void postSticky(Object event){
        EventBus.getDefault().postSticky(event);
    }
/**
     * 移除所有的粘性訂閱事件
     */
    public static void removeAllStickyEvents(){
        EventBus.getDefault().removeAllStickyEvents();
    }
}

 

案例:從MainActivity分別跳轉FirstActivity和SecondActivity,跳轉SecondActivity時傳送粘性事件,返回到MainActivity時傳送普通事件

 

程式碼實戰:

BaseActivity:

public abstract class BaseActivity extends AppCompatActivity {

    private String TAG="BaseActivity";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResId());
        initView();
        initData();

        if(isRegisteredEventBus()){//放到initView後面  防止 接收到event事件需要更新UI的時候 佈局還未初始化完成
            EventBusUtils.register(this);
        }

    }

    @Override
    protected void onDestroy() {
        release();
        if(isRegisteredEventBus()){
            EventBusUtils.unregister(this);
        }
        super.onDestroy();
    }

    /**
     * 獲取佈局
     * @return 佈局ID
     */
    protected abstract int getLayoutResId();

    /**
     * 初始化檢視
     */
    protected void initView(){}

    /**
     * 初始化資料
     */
    protected void initData(){}

    /**
     * 釋放資源
     */
    protected void release(){}



    /**
     * 是否註冊事件分發
     * @return true:註冊    false:不註冊 預設不註冊
     */
    protected boolean isRegisteredEventBus(){
        Log.e(TAG, "isRegisteredEventBus: 00000");
        return false;
    }

}

MainActivity:

public class MainActivity extends BaseActivity implements View.OnClickListener {

    private String TAG="MainActivity";
    private TextView tv;
    private Button bt1,bt2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected int getLayoutResId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initView() {
        super.initView();
        tv=findViewById(R.id.tv);
        bt1=findViewById(R.id.bt1);
        bt2=findViewById(R.id.bt2);
        bt1.setOnClickListener(this);
        bt2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {


        switch (v.getId()){
            case R.id.bt1:
                FirstActivity.startActivity(MainActivity.this);
                break;
            case R.id.bt2:
                EventMessage eventMessage=new EventMessage(EventCode.EVENT_E,"來自mainactivity的msg");
                EventBusUtils.postSticky(eventMessage);
                SecondActivity.startActivity(MainActivity.this);
                break;
        }
    }


    @Subscribe(threadMode = ThreadMode.MAIN)
    public void  onReceiveEvent(EventMessage msg){
        String m=(String) msg.getData();
        if(msg.getCode()==EventCode.EVENT_A){
            tv.setText(m);
        }else if(msg.getCode()==EventCode.EVENT_B){
            tv.setText(m);
        }
    }

    @Override
    protected boolean isRegisteredEventBus() {
        Log.e(TAG, "isRegisteredEventBus: 1111" );
        return true;
    }
}

FirstActivity:

public class FirstActivity extends BaseActivity implements View.OnClickListener {
    private String TAG="FirstActivity";
    private TextView tv;
    private Button bt;

    /**
     * 啟動activity
     */
    public static void startActivity(Activity srcActivity) {
        Intent intent=new Intent(srcActivity,FirstActivity.class);
        srcActivity.startActivity(intent);
    }
    @Override
    protected int getLayoutResId() {
        return R.layout.activity_first;
    }

    @Override
    protected void initView() {
        super.initView();
        tv=findViewById(R.id.tv);
        bt=findViewById(R.id.bt1);
        bt.setOnClickListener(this);
    }

    @Override
    protected void initData() {
        super.initData();
    }
    
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt1:
                EventMessage msg=new EventMessage(EventCode.EVENT_A,"來自firstactivity的訊息");
                EventBusUtils.post(msg);
                this.finish();
                break;
        }
    }
}

SecondActivity:

public class SecondActivity extends BaseActivity implements View.OnClickListener {
    private String TAG="SecondActivity";
    private TextView tv;
    private Button bt;
    public static void startActivity(Activity activity){
        Intent intent=new Intent(activity,SecondActivity.class);
        activity.startActivity(intent);

    }


    @Override
    protected int getLayoutResId() {
        return R.layout.activity_second;
    }

    @Override
    protected void initView() {
        super.initView();
        tv=findViewById(R.id.tv);
        bt=findViewById(R.id.bt1);
        bt.setOnClickListener(this);
    }

    @Override
    protected void initData() {
        super.initData();
    }

    @Override
    protected boolean isRegisteredEventBus() {
        return true;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt1:
                EventMessage msg=new EventMessage(EventCode.EVENT_B,"來自secondactivity的訊息");
                EventBusUtils.post(msg);
                this.finish();
                break;
        }
    }
    @Subscribe(threadMode = ThreadMode.MAIN,sticky=true)
    public void onReceiveEvent(EventMessage msg){
        Log.e(TAG, "onReceiveEvent: msg:"+msg.toString() );
        if (msg.getCode()==EventCode.EVENT_E){
            tv.setText((String)msg.getData());
        }
    }
}

 

5.注意

1.在基類中封裝時,注意註冊EventBus放到初始化檢視後面,防止收到粘性事件需要更新UI時 佈局還未初始化玩  會報空指標異常

 

6.參考

EventBus的優雅封裝