EventBus詳解
1.前言
EventBus是一款針對Android優化的釋出/訂閱事件匯流排。可以替代廣播、startActivityForResult、Handler、非同步回撥等來實現各元件間、元件與後臺執行緒間的通訊。它的優點是開銷小,程式碼更優雅,以及將傳送者和接收者解耦。
通常我們在使用EventBus的時候都是直接需要接收通訊的Activity/Fragment中通過EventBus.getDefault().register(this)訂閱事件,在需要發起通訊的邏輯直接呼叫EventBus.getDefault().post(Object event)來發布事件。但是要是一個專案中有很多地方都使用EventBus來通訊,比如重新登入後更新各個頁面的登入狀態,或者是接收到通知更新訊息提示等,都這樣直接使用的話程式碼重複率很高,並且呢,如果以後升級或者更換EventBus時,各個地方都要修改,這就比較麻煩了。因此我一般是將EventBus的釋出和訂閱封裝到BaseActivity/BaseFragment中。
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.參考