EventBus 是一种为 Android 而优化设计的发布/订阅事件总线
有了这个,对于一个事件,你只要关心发送和接收就行了,而其中的收集、分发等都交给 EventBus 来处理,你不需要做任何事
使用方法
首先导入依赖包
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'org.greenrobot:eventbus:3.0.0'
testCompile 'junit:junit:4.12'
}
第一步,定义一个事件类
MyEvent
public class MyEvent {
private String msg;//需要传递的数据(可以是复杂bean对象)
public MyEvent(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
定义一个订阅方法,可以使用 @Subscribe 注解来指定订阅方法所在的线程:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MyEvent event) {
String msg=event.getMsg();//获取传递过来的信息
};
注册和反注册你的订阅方法。比如在 Android 中,Activity 和 Fragment 通常在如下的生命周期中进行注册和反注册:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
3.发送事件:
EventBus.getDefault().post(new MyEvent("msg"));
使用非常简单
EventBus 原理分析
EventBus.getDefault()
来看源码
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
// key 为事件的类型,value 为所有订阅该事件类型的订阅者集合
subscriptionsByEventType = new HashMap<>();
// key 为某个订阅者,value 为该订阅者所有的事件类型
typesBySubscriber = new HashMap<>();
// 粘性事件的集合,key 为事件的类型,value 为该事件的对象
stickyEvents = new ConcurrentHashMap<>();
// 主线程事件发送者
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
// 子线程事件发送者
backgroundPoster = new BackgroundPoster(this);
// 异步线程事件发送者
asyncPoster = new AsyncPoster(this);
// 索引类的数量
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
// 订阅方法查找者
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
// 是否打印订阅者异常的日志,默认为 true
logSubscriberExceptions = builder.logSubscriberExceptions;
// 是否打印没有订阅者的异常日志,默认为 true
logNoSubscriberMessages = builder.logNoSubscriberMessages;
// 是否允许发送 SubscriberExceptionEvent ,默认为 true
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
// 是否允许发送 sendNoSubscriberEvent ,默认为 true
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
// 是否允许抛出订阅者的异常,默认是 false
throwSubscriberException = builder.throwSubscriberException;
// 是否支持事件继承,默认是 true
eventInheritance = builder.eventInheritance;
// 创建线程池
executorService = builder.executorService;
}
平时的我们经常调用的 EventBus.getDefault() 代码,其实是获取了 EventBus 类的单例。在初始化这块调用的是EventBusBuilder的默认参数,在 EventBus 构造器中初始化了一堆的成员变量.
EventBus.register(Object subscriber)
事件订阅者必须调用 register(Object subscriber) 方法来进行注册,一起来看看在 register(Object subscriber) 中到底做了一些什么:
public void register(Object subscriber) { // 得到订阅者的类 class Class<?> subscriberClass = subscriber.getClass(); // 找到该 class 下所有的订阅方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
在 register(Object subscriber) 中,利用 subscriberMethodFinder.findSubscriberMethods 方法找到订阅者 class 下所有的订阅方法,然后用 for 循环建立订阅关系。
然后就是轮到了 subscribe(subscriber, subscriberMethod) 方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { // 得到订阅方法的事件类型 Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 根据订阅方法的事件类型得到所有订阅该事件类型的订阅者集合 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { // 如果 subscriptions 已经包含了,抛出异常 if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } // 根据该 subscriberMethod 优先级插入到 subscriptions 中 int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } // 放入 subscribedEvents 中,key:订阅者 value:该订阅者的所有订阅事件的类型 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); // 如果订阅的方法支持 sticky if (subscriberMethod.sticky) { // 如果支持事件继承 if (eventInheritance) { // Existing sticky events of all subclasses of eventType have to be considered. // Note: Iterating over all events may be inefficient with lots of sticky events, // thus data structure should be changed to allow a more efficient lookup // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>). Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); // 遍历 stickyEvents for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); // 判断 eventType 类型是否是 candidateEventType 的父类 if (eventType.isAssignableFrom(candidateEventType)) { // 得到对应 eventType 的子类事件,类型为 candidateEventType Object stickyEvent = entry.getValue(); // 发送粘性事件给 newSubscription checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { // 拿到之前 sticky 的事件,然后发送给 newSubscription Object stickyEvent = stickyEvents.get(eventType); // 发送粘性事件给 newSubscription checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
其实 subscribe(subscriber, subscriberMethod) 方法主要就做了三件事:
得到 subscriptions ,然后根据优先级把 subscriberMethod 插入到 subscriptions 中;
将 eventType 放入到 subscribedEvents 中;
如果订阅方法支持 sticky ,那么发送相关的粘性事件。
unregister(Object subscriber)
首先从typesBySubscriber获取当前订阅者,然后找到此订阅者的所有类型,将此订阅者的所有类型从subscriptionsByEventType表里删除。接着再把此订阅者从typesBySubscriber中删除
看看 unregister(Object subscriber) 的源码:
public synchronized void unregister(Object subscriber) { // 通过 subscriber 来找到 subscribedTypes List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { // 解除每个订阅的事件类型 unsubscribeByEventType(subscriber, eventType); } // 从 typesBySubscriber 中移除 typesBySubscriber.remove(subscriber); } else { Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
post(Object event)
分析下发送事件 post(Object event) 的源码:
在 post(Object event) 中,首先根据 currentPostingThreadState 获取当前线程状态 postingState 。currentPostingThreadState 其实就是一个 ThreadLocal 类的对象,不同的线程根据自己独有的索引值可以得到相应属于自己的 postingState 数据。然后把事件 event 加入到 eventQueue 队列中排队。只要 eventQueue 不为空,就不间断地发送事件private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } }; public void post(Object event) { // 得到当前线程的 postingState PostingThreadState postingState = currentPostingThreadState.get(); // 加入到队列中 List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); // 如果没有持续在发送事件,那么开始发送事件并一直保持发送ing if (!postingState.isPosting) { postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { // 发送单个事件 postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
EventBus 是一款典型的运行观察者模式的开源框架,设计巧妙,代码也通俗易懂,值得我们学习。