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.参考