EventBus
github地址:https://github.com/greenrobot/EventBus
一、概述
EventBus是一个Android的事件发布、订阅框架,通过解耦发布者和订阅者,简化Android事件的传递。这里的事件可以理解为消息。事件传递既可用于Android四大组件间通讯,Fragment之间,也可以用于异步线程和主线程之间的通讯。
传统的事件传递方式:Handler、Intent、BroadcastReciver、Interface回调。
EventBus优点:
代码简洁、使用简单,并将事件发布和订阅充分解耦。
既然是有关于事件的发布和订阅,那么发布者和订阅者的关系又是怎样的呢?
事件的发布者可以发布多个事件,发布者同时也可以是订阅者,订阅者可以订阅多个事件。
事件:分为一般事件和Sticky黏性事件。
Sticky事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型的事件,依然能收到该类型事件最近一个Sticky事件。
二、如何使用EventBus
(1)首先在gradle文件中添加EventBus的依赖
compile 'org.greenrobot:eventbus:3.0.0'
(2)在相关Activity中的onCreat()、onDestory()注册和解注EventBus
//把当前类注册为订阅者(接收者)
EventBus.getDefault().register(this);
//解除注册当前类(同广播一样,一定要调用,否则会内存泄露)
EventBus.getDefault().unregister(this);
(3)注册了订阅者之后,我们需要一个回调方法onMessageEvent接受事件订阅。
当我们订阅的事件开始发送后就会回调这个方法。通过自定义MessageEvent对象来区分发送的事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
(4)事件发送
订阅的事件发送,就像广播发送需要sendBroadcast,EventBus需要post(event)。
/**
* 这里的event类型必须和上面我们onEvent()方法的参数类型一致,
* 只有参数类型一致,才会收到发送的信息
*/
EventBus.getDefault().post(event);
三:EventBus工作原理
注册里面的逻辑
1.调用register()方法注册订阅者A。
2.遍历订阅者A所有的的订阅方法,把A订阅的所有事件作为key,把所有订阅事件的订阅者作为value,存储到 Map<事件,List<订阅这个事件的订阅者>>中。
Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
里面封装了一个对象,有方法、线程模式、事件类型、优先级、是否黏性事件、
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
}
3.以A的类名为 key,所有 onEvent 参数类型的类名组成的集合为 value,存入 Map<订阅者,List<订阅的事件>>。
Map, CopyOnWriteArrayList> subscriptionsByEventType =new HashMap<>();
final class Subscription {
final Object subscriber;//订阅者
final SubscriberMethod subscriberMethod;//订阅对象
}
4.如果是订阅了黏性事件的订阅者,从黏性事件缓存区获取之前发送过的粘滞事件,响应这些黏性事件。
发送事件的逻辑
1、取当前线程的发送事件封装数据,并从封装的数据中拿到发送事件的事件队列。
2、将要发送的事件加入到事件队列中去。
3、循环,每次发送队列中的一条事件给所有订阅了这个事件的订阅者。
4、如果是子事件可以响应父事件的事件模式,需要先将这个事件的所有父类、接口、父类的接口、父类接口的父类都找到,并让订阅了这些父类信息的订阅者也都响应这条事件。
响应事件的逻辑
1、首先判断事件的响应线程模式,响应模式分为四种:
PostThread 在哪个线程调用的post()方法,就在哪个线程执行响应方法。
MainThread 无论是在哪个线程调用的post()方法,最终都在主线程执行响应方法。
BackgroundThread 无论是在哪个线程调用的post()方法,最终都在后台线程执行响应方法。(串行执行,一次只执行一个任务,其他任务在队列中处于等待状态)
Async 无论是在哪个线程调用的post()方法,最终都在后台线程执行响应方法。(并行执行,只要有任务就开一个线程让他执行)
取消注册的逻辑
1、首先是调用unregister()方法拿到要取消注册的订阅者B。
2、从这个类订阅的时候存入的 Map<订阅者,List<订阅的事件>> 中,拿到这个类的订阅事件集合。
3、遍历订阅时间集合,在注册的时候存入的 Map<事件,List<订阅这个事件的订阅者>> 中将对应订阅事件的订阅者集合中的这个订阅者移除。
4、将步骤2中的 Map<订阅者,List<订阅的事件>> 中这个订阅者相关的 Entry 移除。
四:EventBus总结
背景:ActivityA、ActivityB简称A、B。AB订阅了事件,然后C发布这个事件。
问题1:C发布的事件是怎么通知AB的呢?
问题2:线程之间是如何进行操作的呢?