最近在看EventBus的源码,想看看它好在哪里,跟广播相比,如果只是在app内通知获取数据,那用eventBus要相对方便得多,但如果是跨进程,那还是用广播吧,而且EventBus一次post只能传一个类,除非这个onEvent没有其它重载的函数,不然会抛异常:
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType) ;
看了整个流程,第一个重要的类是:SubscriberMethodFinder,涉及到EventBus的订阅跟发布。
如果是系统类了就跳过获取,再把这个类以及它的父类相关的onEvent方法找到,加入到subscriberMethods里去。
List
findSubscriberMethods
(Class> subscriberClass) {
List subscriberMethods
;
synchronized
(
methodCache
) {
subscriberMethods =
methodCache
.get(subscriberClass)
;
}
if
(subscriberMethods !=
null
) {
return
subscriberMethods
;
}
subscriberMethods =
new
ArrayList()
;
Class> clazz = subscriberClass
;
HashMap
,
Class> eventTypesFound =
new
HashMap
,
Class>()
;
StringBuilder methodKeyBuilder =
new
StringBuilder()
;
//
循环获取父类
while
(clazz !=
null
) {
String name = clazz.getName()
;
if
(name.startsWith(
"java."
) || name.startsWith(
"javax."
) || name.startsWith(
"android."
)) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
try
{
// This is faster than getMethods, especially when subscribers a fat classes like Activities
Method[] methods = clazz.getDeclaredMethods()
;
filterSubscriberMethods(subscriberMethods
,
eventTypesFound
,
methodKeyBuilder
,
methods)
;
}
catch
(Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
Method[] methods = subscriberClass.getMethods()
;
subscriberMethods.clear()
;
eventTypesFound.clear()
;
filterSubscriberMethods(subscriberMethods
,
eventTypesFound
,
methodKeyBuilder
,
methods)
;
break;
}
clazz = clazz.getSuperclass()
;
}
if
(subscriberMethods.isEmpty()) {
throw new
EventBusException(
"Subscriber "
+ subscriberClass +
" has no public methods called "
+
ON_EVENT_METHOD_NAME
)
;
}
else
{
synchronized
(
methodCache
) {
methodCache
.put(subscriberClass
,
subscriberMethods)
;
}
return
subscriberMethods
;
}
}
如果是以onEvent开头的,就继续看这个函数的名称,看是放在哪个线程,先分析filerSubscriberMethobs函数。
事件类型是由方法名+第一个参数类型组成,new 一个由方法名,线程,事件类型组成的订阅者放到这个与这个类相应的list里。
private void
filterSubscriberMethods
(List subscriberMethods
,
HashMap
,
Class> eventTypesFound
,
StringBuilder methodKeyBuilder
,
Method[] methods) {
for
(Method method : methods) {
String methodName = method.getName()
;
if
(methodName.startsWith(
ON_EVENT_METHOD_NAME
)) {
int
modifiers = method.getModifiers()
;
Class> methodClass = method.getDeclaringClass()
;
if
((modifiers & Modifier.
PUBLIC
) !=
0
&& (modifiers &
MODIFIERS_IGNORE
) ==
0
) {
Class>[] parameterTypes = method.getParameterTypes()
;
if
(parameterTypes.
length
==
1
) {
ThreadMode threadMode = getThreadMode(methodClass
,
method
,
methodName)
;
if
(threadMode ==
null
) {
continue;
}
//
第一个参数类型
Class> eventType = parameterTypes[
0
]
;
methodKeyBuilder.setLength(
0
)
;
methodKeyBuilder.append(methodName)
;
methodKeyBuilder.append(
'>'
).append(eventType.getName())
;
String methodKey = methodKeyBuilder.toString()
;
Class methodClassOld = eventTypesFound.put(methodKey
,
methodClass)
;
//
如果子类重写了父类的
onEvent
方法,只放入子类的
if
(methodClassOld ==
null
|| methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
subscriberMethods.add(
new
SubscriberMethod(method
,
threadMode
,
eventType))
;
}
else
{
// Revert the put, old class is further down the class hierarchy
eventTypesFound.put(methodKey
,
methodClassOld)
;
}
}
}
else if
(!
skipMethodVerificationForClasses
.containsKey(methodClass)) {
Log.d(EventBus.
TAG
,
"Skipping method (not public, static or abstract): "
+ methodClass +
"."
+ methodName)
;
}
}
}
}
看看onEvent后是什么字段,比如:MainThread。
private
ThreadMode
getThreadMode
(Class> clazz
,
Method method
,
String methodName) {
String modifierString = methodName.substring(
ON_EVENT_METHOD_NAME
.length())
;
ThreadMode threadMode
;
if
(modifierString.length() ==
0
) {
threadMode = ThreadMode.
PostThread
;
}
else if
(modifierString.equals(
"MainThread"
)) {
threadMode = ThreadMode.
MainThread
;
}
else if
(modifierString.equals(
"BackgroundThread"
)) {
threadMode = ThreadMode.
BackgroundThread
;
}
else if
(modifierString.equals(
"Async"
)) {
threadMode = ThreadMode.
Async
;
}
else
{
if
(!
skipMethodVerificationForClasses
.containsKey(clazz)) {
throw new
EventBusException(
"Illegal onEvent method, check for typos: "
+ method)
;
}
else
{
threadMode =
null;
}
}
return
threadMode
;
}
从这个类可知,这个类是用来在调用EventBus.getDefault().register(this)的时候,获取当前这个类的订阅方法的,以方法+第一个参数类型来做为eventType来做为订阅类型,统一放到SubscribeMethod里。
接下来就可以讲订阅流程了。
首先是
/** 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,EventBus有几个register函数,但都会统一调用下面这个函数。
private synchronized void
register
(Object subscriber
, boolean
sticky
, int
priority) {
//
获得与这个类相对应的订阅方法,放到
SubScriberMethod
List subscriberMethods =
subscriberMethodFinder
.findSubscriberMethods(subscriber.getClass())
;
for
(SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber
,
subscriberMethod
,
sticky
,
priority)
;
}
}
从这个函数可知,会先获取到这个类的onEvnent的订阅方法,在对每个方法进行订阅。在对这个类的每个函数进行注册时,做了三件事,
第一件是在subscriptionsByEventType里放入这个eventType的订阅者:Subsctiption(由类类型,方法,优先级),并且按优先级排序。第二件事在typesByScubscriptions是放入类型对应该的所有订阅,最后还要用于解除注册。第三步是
判断sticky;如果为true,从stickyEvents中根据eventType去查找有没有stickyEvent,如果有则立即发布去执行。stickyEvent其实就是我们post时的参数
// Must be called in synchronized block
private void
subscribe
(Object subscriber
,
SubscriberMethod subscriberMethod
, boolean
sticky
, int
priority) {
Class> eventType = subscriberMethod.
eventType
;
CopyOnWriteArrayList subscriptions =
subscriptionsByEventType
.get(eventType)
;
Subscription newSubscription =
new
Subscription(subscriber
,
subscriberMethod
,
priority)
;
//
放入一个同个类作为
eventType
也就是参数
0
的订阅列表
if
(subscriptions ==
null
) {
subscriptions =
new
CopyOnWriteArrayList()
;
subscriptionsByEventType
.put(eventType
,
subscriptions)
;
}
else
{
if
(subscriptions.contains(newSubscription)) {
throw new
EventBusException(
"Subscriber "
+ subscriber.getClass() +
" already registered to event "
+ eventType)
;
}
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);
int
size = subscriptions.size()
;
//
按优先级插入
for
(
int
i =
0
;
i <= size
;
i++) {
if
(i == size || newSubscription.
priority
> subscriptions.get(i).
priority
) {
subscriptions.add(i
,
newSubscription)
;
break;
}
}
//
存放一个类有多少个订阅方法
List> subscribedEvents =
typesBySubscriber
.get(subscriber)
;
if
(subscribedEvents ==
null
) {
subscribedEvents =
new
ArrayList>()
;
typesBySubscriber
.put(subscriber
,
subscribedEvents)
;
}
subscribedEvents.add(eventType)
;
if
(sticky) {
//
是否支持继承,默认是支持
//
判断
sticky
;如果为
true
,从
stickyEvents
中根据
eventType
去查找有没有
stickyEvent
,如果有则立即发布去执行。
stickyEvent
其实就是我们
post
时的参数
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).
Set
,
Object>> entries =
stickyEvents
.entrySet()
;
for
(Map.Entry
,
Object> entry : entries) {
Class> candidateEventType = entry.getKey()
;
if
(eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue()
;
checkPostStickyEventToSubscription(newSubscription
,
stickyEvent)
;
}
}
}
else
{
Object stickyEvent =
stickyEvents
.get(eventType)
;
checkPostStickyEventToSubscription(newSubscription
,
stickyEvent)
;
}
}
}
接下来是解除注册:
找到这个类的所有订阅类型并移除这个订阅类。
/** Unregisters the given subscriber from all event classes. */
public synchronized void
unregister
(Object subscriber) {
//
找到这个类的所有订阅类型
List> subscribedTypes =
typesBySubscriber
.get(subscriber)
;
if
(subscribedTypes !=
null
) {
for
(Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber
,
eventType)
;
}
typesBySubscriber
.remove(subscriber)
;
}
else
{
Log.w(
TAG
,
"Subscriber to unregister was not registered before: "
+ subscriber.getClass())
;
}
}
找到与这个订阅类型相关的订阅类,移除
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void
unsubscribeByEventType
(Object subscriber
,
Class> eventType) {
//
找到与这个订阅类型的订阅类,移除
List 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--
;
}
}
}
}