您的位置:首页 > 其它

EventBus源码分析(一):入口函数提纲挈领(2.4版本)

2016-07-01 15:58 513 查看
EventBus源码分析(一):入口函数提纲挈领(2.4版本)

EventBus源码分析(二):register方法保存事件的订阅者列表(2.4版本)

EventBus源码分析(三):post方法发布事件【获取事件的所有订阅者,反射调用订阅者事件处理方法】(2.4版本)

EventBus源码分析(四):线程模型分析(2.4版本)

EventBus源码解读详细注释(1)register的幕后黑手

EventBus源码解读详细注释(2)MainThread线程模型分析

EventBus源码解读详细注释(3)PostThread、MainThread、BackgroundThread、Async四种线程模式的区别

EventBus源码解读详细注释(4)register时刷新的两个map

EventBus源码解读详细注释(5)事件消息继承性分析 eventInheritance含义

EventBus源码解读详细注释(6)从事件发布到事件处理,究竟发生了什么!

本文是EventBus源码分析的第一篇文章,不拘泥于具体的实现细节,从宏观上把握EventBus的设计思路,而EventBus总体的设计思路为:

EventBus实例保存了事件到订阅者列表的map,发布事件的时候,从该map中取出该事件的所有订阅者,在规定的线程中反射调用所有订阅者的事件处理方法。

DCL单例创建EventBus对象

EventBus提供了静态方法创建EventBus对象,实现方式为标准的DCL双检锁的单例模式。DCL双检锁分为两部分:

静态易变的defaultInstance属性

静态的getDefault方法

...
static volatile EventBus defaultInstance;
...
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}


但是EventBus并非严格的DCL单例模式,因为构造器并不是私有的,因此并不能保证EventBus实例的唯一性。不同实例之间是总线隔离的,即EventBus实例A发布的事件event并不能被EventBus实例B订阅接受。

register方法向EventBus注册订阅者

register(this)就是在当前类(Activity等)遍历所有方法,按照EventBus事件处理方法的命名规则约束(onEvent开头,只有一个参数,非static,非abstract的public方法)过滤出事件处理方法然后进行存储。

因此register主要分为两步:

找到订阅者订阅的所有事件

对每个订阅者订阅的所有事件,逐一进行订阅

private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
`
}


EventBus针对每一个事件,维护了一个订阅了这个事件的订阅者的列表,并且用HashMap来保存,HashMap的键为事件的Class,值为该事件的订阅者列表。

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;


该HashMap有两点需要注意:

该HashMap是对象属性不是类属性,因此不同的EventBus实例的该属性是不同的,这也是不同EventBus实例之间总线隔离的原因

订阅者列表并没有通过ArrayList实现,为了达到线程并发安全,采用CopyOnWriteArrayList

post方法向EventBus发布事件

EventBus存储了事件到及该事件的订阅者列表,因此发布事件就应该是找到该事件的订阅者列表,对每一个订阅者通过反射调用事件处理方法。

/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);

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;
}
}
}


post方法首先获取了事件发布者的线程状态,从该线程状态中获取事件队列,然后不停得处理队列中的事件,直到队列为空

while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}


postSingleEvent方法里边进一步调用了postSingleEventForEventType方法,找到该事件的订阅者列表

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}


首先在同步代码块中获取该事件的订阅者列表

synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}


然后遍历订阅者列表,对每一个订阅者进行处理

for (Subscription subscription : subscriptions) {
...
postToSubscription(subscription, event, postingState.isMainThread);
...
}


而postToSubscription方法就是根据不同的线程模式,在不同的线程中反射调用订阅者的事件处理方法。

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread:
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);
}
}


unregister方法-订阅者向EventBus解注册

为了防止内存泄露,像Android中的广播或者其他的订阅者模式,有注册就有解注册,EventBus也不例外。unregister方法一般在与调用register方法对称的生存周期回调中调用。

/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}


在register注册的时候,保存了两个重要的HashMap,其中一个就是上文提到的事件到订阅者列表的map,该map用于发布事件的时候寻找该事件的订阅者列表,然后通过反射调用订阅者的事件处理方法。第二个就是订阅者到事件列表的map,表明了该订阅者订阅了哪些事件,主要用于解注册。

private final Map<Object, List<Class<?>>> typesBySubscriber;


unregister方法先从此map中找到该订阅者订阅的所有事件

List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);


然后对每一个事件进行解注册

for (Class<?> eventType : subscribedTypes) {
unubscribeByEventType(subscriber, eventType);
}


最后从此map中删除该订阅者

typesBySubscriber.remove(subscriber);


本文结束,接下来会深入源码,从细节上探索EventBus的设计思路。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码