Android 开源框架 ( 七 ) 事件总线---EventBus
一.引言
与四大组件之一的BroadCast广播比较,广播主要监听系统级事件,比如网络切换,电池电量等属于进程间的通信,EventBus 是进程内的通信。
了解BroadCast 可以查看该文章:Android 四大组件 (三) BroadcastReceiver 介绍
了解BroadCast 可以查看该文章:Android 四大组件 (三) BroadcastReceiver 介绍
二.基本使用
引入类库:
compile 'com.jakewharton:butterknife:8.5.1'
页面打开时候初始化并注册EventBus
//初始化 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //注册 EventBus EventBus.getDefault().register(this); }
页面销毁时候解除EventBus注册
//销毁 EventBus @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }
发布事件 publish
//发布事件 EventBus.getDefault().post(new EventBean("我来自第二个页面的触发"));
接受者 subscribe.注意方法名可以随便取,但是参数类型与publish发布者的保持一致. 这里是EventBean
//订阅者事件,处理事件反馈的消息 @Subscribe public void OnEvent(EventBean bean) { //拿到发布者传过来的event事件带的消息 String msgStr = bean.getMsg(); //UI打印出拿到的消息 tvFirst.setText(msgStr); }
三.ThreadMode 分析
五种 ThreadMode介绍
ThreadMode.MAIN 订阅者将在Android的主线程(有时称为UI线程)中被调用。如果发布线程是主线程,则将直接调用事件处理程序方法(与ThreadMode.POSTING中描述的同步)。使用此模式的事件处理程序必须快速返回以避免阻塞主线程. ThreadMode.MAIN_ORDERED 订阅者将在Android的主线程中被调用。该事件总是排队等待以后传递给订阅者。这给事件处理一个更严格和更一致的顺序(因此名字MAIN_ORDERED)。例如,如果使用MAIN线程模式在事件处理程序中发布另一个事件, 则第二个事件处理程序将在第一个事件处理程序之前完成(因为它被同步调用 - 将其与方法调用进行比较)。使用MAIN_ORDERED,第一个事件处理程序将完成,然后第二个将在稍后的时间点被调用(只要主线程有能力). ThreadMode.BACKGROUND 订阅者将在后台线程中被调用。如果发布线程不是主线程,则会在发布线程中直接调用事件处理程序方法。如果发布线程是主线程,则EventBus将使用一个后台线程来按顺序发送所有事件。使用这种模式的事件处理程序应该尽快返回以避免阻塞后台线程。 ThreadMode.ASYNC 事件处理程序方法在单独的线程中调用。这总是独立于发布线程和主线程。发布事件永远不会等待使用此模式的事件处理程序方法。事件处理程序方法应该使用这种模式,如果它们的执行可能需要一些时间, 例如网络访问。避免同时触发大量长时间运行的异步处理程序方法来限制并发线程的数量。EventBus使用线程池有效地重用已完成异步事件处理程序通知中的线程。 ThreadMode.POSTING这是默认的。订阅者将在发布该事件的同一个线程中被调用。事件传递是同步完成的,所有订阅者一旦发布完成就被调用。这个ThreadMode意味着最小的开销,因为它避免了完全的线程切换。 因此,对于已知完成的简单任务而言,这是推荐的模式,其时间很短,不需要主线程。使用这种模式的事件处理程序应该快速返回以避免阻塞发布线程,这可能是主线程。
源码查看下五种ThreadMode不同处理方式:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { //发送和订阅者在同一线程内 case POSTING: invokeSubscriber(subscription, event); break; //主线程 case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; // case MAIN_ORDERED: if (mainThreadPoster != null) { mainThreadPoster.enqueue(subscription, event); } else { // temporary: technically not correct as poster not decoupled from subscriber invokeSubscriber(subscription, event); } break; //后台,不能并发处理 case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; //子线程 异步并发处理 case ASYNC: asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
四.粘性事件
简单说就是: 发送事件之后再订阅该事件也能收到该事件。同样Android 中也有同样的粘性事件机制,如 粘性广播(Sticky Broadcast).粘性事件使用场景:
一些事件进行信息感兴趣的事件后发布。 例如,一个事件信号,一些初始化完成。 或者如果你有传感器位置数据和你想抓住最近的值。 而不是实现自己的缓存,您可以使用黏性的事件。 EventBus保持过去的事件的特定类型在内存中。 黏性的事件可以交付给用户或显式查询。 因此,你不需要任何特殊的逻辑来考虑可用的数据。
粘性使用示例:
// 1创建一个粘性事件类 public class StickyEvent { public String msg; public StickyEvent(String msg) { this.msg = msg; } }
// 2 发送粘性事件 EventBus.getDefault().postSticky(new StickyEvent("我是粘性事件"));
// 3 接收粘性事件 @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void StickyEventBus(StickyEvent event){ // 显示接收的数据 tv_eventbus_send_result.setText(event.msg); }
// 4.接收粘性事件数据按钮的点击事件处理 bt_eventbus_send_sticky.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //true第一次点击,防止重复注册 if(isFirstFlag) { isFirstFlag = false; // 4 注册 EventBus.getDefault().register(EventBusSendActivity.this); } } });
@Override protected void onDestroy() { super.onDestroy(); // 5 解注册 EventBus.getDefault().removeAllStickyEvents(); EventBus.getDefault().unregister(EventBusSendActivity.this); }