-
前言
EventBus可以看成主要由两个部分组成,观察者和信息发布者。大致的流程是,android组件通过register方法注册成观察者,并通过注解@SubScribe注明处理消息的函数,eventbus会把所有的观察者和观察者中处理消息的函数保存在map中,当发布消息的时候,会根据发布消息的对象类型来检索哪些对象和方法需要处理此类信息,然后通过反射Method的invoke方法来执行注册函数。所以查看源码要从两个方面入手,本篇只介绍如何eventbus是处理观察者的模块。
-
注册解除注册
首先根据demo中的注册解除注册来看注册过程。
public class EventBusActivity extends Activity {
@BindView(R.id.content_text)
TextView contentView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
ButterKnife.bind(this);
//注册观察者
EventBus.getDefault().register(this);
}
/**
* 处理消息,只能是一个参数,通过参数识别处理哪个消息。发送的消息和参数匹配才会处理。
* @param me 处理的消息对象
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageObject me) {
String content = me.getObject();
contentView.setText(content);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(EventBus.getDefault().isRegistered(this)) {
//取消注册
EventBus.getDefault().unregister(this);
}
}
}
首先通过register(Object o)方法进行注册,然后通过@Subscribe()注解来标明处理函数。因为发布消息之后,消息的处理最终也是通过Method.Invoke(Object,Method)来实现的。所以通过register必须把注册者对象和注册者函数(注册者中处理消息的函数)保存好。不多说,先看register源码。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//将观察者类中的所有注册函数找出来。
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
findSubscriberMethods()见名知意应该是将注册者类中所有的注册函数检索出来。然后通过subscribe()方法将注册者对象和对象中所有的注册函数保存。然后再看findSubscriberMethods()函数。
/**
* 查找指定观察者中的所有注册方法
* @param subscriberClass 注册到eventbus中的类
* @return 类中的所有注册方法
*/
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//通过缓存查找
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
//若缓存中有直接返回
return subscriberMethods;
}
//builder中的变量默认false,如果为true则强制使用反射
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
//判断指定类subscriberClass中的注册方法,如果为空则抛出异常,不为空保存到map,并返回方法数列表
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
在这里先通过查看缓存(METHOD_CACHE)中是否已经存储观察者对象,如果有,则直接返回存储内容,没有则遍历获取注册函数。首先看看METHOD_CACHE的定义。他是一个map,用来保存观察者对象和对象中所有的注册方法。
/**
* key值是注册到eventbus中的观察者类,value是类中的所有注册函数的信息
*/
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
看到这里需要对一个概念有所了解,SubscriberMethod,它保存了注册函数中的函数信息。其中eventType需要注意,他就是注册函数中形参的数据类型,也就是发布者发布消息对象的类型。
/**
* 主要描述注册方法的各个属性信息
* */
public class SubscriberMethod {
final Method method;
//线程属相
final ThreadMode threadMode;
//注册方法中形参的类型,就是表示传递消息的类型。
final Class<?> eventType;
final int priority;
//是否是黏性广播
final boolean sticky;
回过头来看findSubscribeMethod()没有缓存,会执行到findUserInfo().
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//在FIND_STATE_POOL中查找,没有则直接new一个。
FindState findState = prepareFindState();
//初始化findstate,参数是观察者类。
findState.initForSubscriber(subscriberClass);
//刚刚初始化之后findState的clazz表示的就是观察者类。遍历clazz的所有父类
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
//findState.subscriberInfo默认为空
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
在这里遍历注册者父类获取注册函数。因为subscriberInfo默认为空,所以需要进入findUsingReflectInSingleClass()。获取method的核心也在这里得以体现。
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//getDeclaredMethods只返回此类中声明的所有方法,而getMethods把继承的所有父类中的公共方法都返回。
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
//遍历此类中的所有方法
for (Method method : methods) {
//获取方法修饰符
int modifiers = method.getModifiers();
//必须是public函数,并且不能被Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC修饰
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//按顺序返回此方法中形参的类型
Class<?>[] parameterTypes = method.getParameterTypes();
//必须只有一个参数其他情况通过设置属性会抛出异常
if (parameterTypes.length == 1) {
//获取函数的Subscribe注解。
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//获取形参的类型
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
//将SubscriberMethod的对象保存到列表中。
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
//findState类
static class FindState {
/**
* 保存观察者中注册方法信息的列表
*/
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
/**
* key为注册方法中参数的类,value为注册方法
*/
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
/**
* key是methodkey,methodkey一般是注册方法名+类名组成的字符串,value是注册方法所在的类。
*/
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
获取Method数组的时候用的getDeclaredMehod()是为了提高效率,遍历注册者对象中的public方法,把含有注解的函数,保存到到findState.subscriberMethods里面。查找结束之后会通过SubscriberMethodFinder#findUsingInfo()来执行getMethodAndRelease来返回到EventBus.register()。 在上文register函数可以看出。获取Method的列表之后会执行subcribe()函数,次函数将观察者和对应的注册函数绑定保存起来。
接着来看subscribe()函数。
//看函数之前要明确2个变量。
/**
*key 为每个观察者中注册函数的参数类,value为subscription的一个,观察者注册函数的参数类型就是
* 消息传递的类型,所以这个map是一个以消息类型为key的map,当发送消息的时候。哪些注册函数需要收到消息。
* 可以通过这个map检索。如果整个项目中通过eventbus post的消息有n中,那么这里的key应该有n个。
*/
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
/**
* key为注册者所在的类,value值为此类中注册@Subscribe的方法接收的参数的类型。就是post的消息类型
* 以观察者为key,保存观察者类中所有注册的消息类型。
*/
private final Map<Object, List<Class<?>>> typesBySubscriber;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取注册方法中形参的类型
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//将已经保存过的eventtype对应的内容取出来。
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//如果对应的消息类型(eventtype)没有存储过,那么new一个列表保存Subscription,然后存入map中
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//如果eventtype对应的value中包含这个SubScription,那么就是重复注册,抛出异常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
//这里主要针对size=0的情况,当subscriptions元素为0, 要将newSubscription保存进入,
//或者是当前的注册函数subscriberMethod的priority比较大,那么要把它按照顺序插入
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//将观察者中包含的所有注册函数保存起来。
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
if (eventInheritance) {
//是否遍历传递的消息类型的父类。此变量默认为true
// 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();
for (Map.Entry<Class<?>, 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);
}
}
}
其中Subscription类包含了两个属性,一个是注册者对象,一个是对象中的一个注册函数SubscriberMethod对象。在此函数中先通过SubscriberMethod对象获取到注册函数参数类型,然后将包含此观察者对象和观察者对象中所有包含此参数类型的注册函数都封装在subscriptionByEventType这个map中。这个Hashmap中保存的内容就会被发布者postevent的时候利用到。注册讲完了接下来要看解除注册:
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
根据观察者对象,在typesBySubscriber中获取到注册信息。通过遍历在unsunbscribeByEventType中把观察者中的所有注册函数和事件全部删除掉。
-
总结
所以在register中一共做了三个事情。
1 查找所有观察者中注册方法的观察事件(即注册函数形参的类型,就是发布消息事件的类型)
2 以此观察事件为key,将所有的观察者信息都保存在subscriptionByEventType中。
3 以观察者为key,将所有的观察事件保存到typesBySubscriber中(即这个观察者中需要处理哪类信息)。
至此eventbus的注册流程走完。eventbus的post流程请看传送门: