Eventbus 3.1.1 源码解析(一)
1、简介
Eventbus在项目中已经接入一段时间了,它是一个 Android 事件发布/订阅框架,作用是为了简化 Android 的事件传递。具体来说,就是它简化了 Android 组件之间的通信,包括四大组件之间、主线程与异步线程之间的通信,同时也解耦了发布者和订阅者的关系,避免了复杂、容易出错的依赖关系和生命周期问题。
下面通过Eventbus的基本使用方法开始,逐步深入对源码进行分析,让自己对这个框架有更深入的理解。
2、简介和基本使用
它主要由四个部分组成,发布者、订阅者、事件和事件传递。
EventBus 关系图2.1 定义事件
我们需要提前定义事件Event的实体类,具体传递什么参数自己定义:
public static class MessageEvent { /* Additional fields if needed */ }
2.2 注册、解注册订阅者
很简单,我们只需要在订阅事件的地方,通过Eventbus进行注册即可:
EventBus.getDefault().register(this);
register是强引用,如果没有解注册,那么强引用会让对象一直被持有而无法回收,导致内存泄露,必须在不需要接收事件时取消注册:
EventBus.getDefault().unregister(this);
2.3 订阅事件
在需要接收事件的地方声明订阅方法,可以指定响应的线程类型、订阅方法的优先级和粘性,后面会具体分析:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
2.4 发送事件
EventBus的post方法用于发送事件:
EventBus.getDefault().post(new MessageEvent());
还支持发送粘性事件:
EventBus.getDefault().postSticky(new MessageEvent());
3、分析源码
3.1 EventBus getDefault()
通过懒汉模式获取EventBus实例:
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
如果不存在,则通过构造函数来初始化实例,传入的DEFAULT_BUILDER是一个默认创建好的EventBusBuilder实例,它包含了创建EventBus实例的一系列自定义参数,通过它我们就可以自定义自己的Eventbus实例,各参数的具体含义如下。
/**
* 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) {
logger = builder.getLogger();
//日志处理器,默认为android.util.Log,也可以自己设置其他的日志处理器
subscriptionsByEventType = new HashMap<>();
//Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
//key为事件的类型,value是所有订阅该事件的List集合
typesBySubscriber = new HashMap<>();
// Map<Object, List<Class<?>>> typesBySubscriber
//订阅者对应订阅事件的集合,key是订阅者,value是订阅者订阅的事件集合
stickyEvents = new ConcurrentHashMap<>();
//保存粘性事件的集合
mainThreadSupport = builder.getMainThreadSupport();
// 主线程接口,可以自定义,默认是Android定义的主线程
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
//主线程发送器
backgroundPoster = new BackgroundPoster(this);
//后台线程发送器
asyncPoster = new AsyncPoster(this);
//异步线程发送器
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//索引数量,为了提高优化性能,3.0以后提供索引,后面再详细介绍
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//用于查找订阅者方法
logSubscriberExceptions = builder.logSubscriberExceptions;
//是否打印订阅者调用订阅函数异常的日志,默认为true
logNoSubscriberMessages = builder.logNoSubscriberMessages;
//是否打印没有订阅者订阅事件的日志,默认为true
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
//订阅者调用订阅函数异常时,是否发送SubscriberExceptionEvent事件,默认为true
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
//没有订阅者订阅事件事,是否发送NoSubscriberEvent事件,默认为true
throwSubscriberException = builder.throwSubscriberException;
//是否抛出SubscriberException异常,默认为false
eventInheritance = builder.eventInheritance;
//是否支持事件继承,默认为 true
executorService = builder.executorService;
//线程池
}
3.2 EventBus register(Object subscriber)
注册订阅者,如果需要订阅事件,必须通过调用register(Object subscriber)方法来注册,才可接收到目标事件
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//找到订阅者类
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//通过传入的订阅者类,找到订阅者的所有订阅方法
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
关于SubscriberMethod,它包含了订阅者方法的一些参数,只在内部给Eventbus和生成的索引来使用,这些参数在编写订阅者方法时就可以自定义:
/** Used internally by EventBus and generated subscriber indexes. */
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.2.1 SubscriberMethodFinder findSubscriberMethods(Class<?> subscriberClass)
SubscriberMethodFinder: 查找订阅方法的类
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass):查找订阅者所有的订阅方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//获取订阅者对应的订阅方法集合的缓存
if (subscriberMethods != null) {
//缓存不为null则直接返回
return subscriberMethods;
}
//ignoreGeneratedIndex:是否忽略注解器生成的索引(索引后面会介绍)
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
//通过反射获取订阅的方法集合
} else {
subscriberMethods = findUsingInfo(subscriberClass);
//通过索引类来获取订阅的方法集合
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
//找不到则抛出”no public methods with the @Subscribe annotation“异常
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
//将订阅者-订阅者方法放进缓存的map集合METHOD_CACHE
return subscriberMethods;
}
}
内部获取订阅者方法的实现有两种
- findUsingReflection(Class<?> subscriberClass)
- findUsingInfo(Class<?> subscriberClass)
第一种:findUsingReflection(Class<?> subscriberClass)
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
//初始化保存和校验订阅方法的类FindState
while (findState.clazz != null) {
//通过反射获取订阅方法
findUsingReflectionInSingleClass(findState);
//查找订阅者的父类
findState.moveToSuperclass();
}
//返回查找到的订阅方法集合
return getMethodsAndRelease(findState);
}
//用于订阅方法的保存和校验
class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
boolean checkAdd(Method method, Class<?> eventType){...}
boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {...}
void moveToSuperclass() {...}
}
FindState:用于订阅方法的保存和校验
通过SubscriberMethodFinder的prepareFindState()方法获得:
//FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
//int POOL_SIZE = 4;
//FIND_STATE_POOL为FindState的缓存池,FindState就可循环利用,避免重复创建过多对象,节省内存。
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
接下来我们看看如何通过反射获取订阅方法
void findUsingReflectionInSingleClass(FindState findState)
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
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
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 方法的类型参数只能有一个
if (parameterTypes.length == 1) {
//通过@Subscribe 注解获得Subscribe注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
//校验方法
if (findState.checkAdd(method, eventType)) {
//解析注解的线程类型
ThreadMode threadMode = subscribeAnnotation.threadMode();
//创建订阅方法对象,并保存至findState的subscriberMethods集合
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");
}
}
}
我们已经一步步了解完如何通过反射获取订阅方法集合,接下来我们要讲第二种获取订阅方法的方式,通过索引获取订阅方法:findUsingInfo(Class<?> subscriberClass)
我们先了解一下索引是什么?
Eventbus3.0之前使用的是运行时注解,获取订阅方法都是通过java的反射机制,而java的反射机制是非常耗费性能的,详细可见这篇文章# java反射的性能问题
因为反射机制是通过对类的所有方法进行扫描,在一些对低端、对性能要求高的真机上,很容易因为性能消耗过高导致体验不佳。
Eventbus3.0开始就使用编译时注解,通过EventBusAnnotationProcessor注解器在编译时就读取@Subscribe()注解并解析,即在Java编译成.class文件时就进行操作,处理@Subscribe所包含的信息,然后生成SubscriberInfoIndex索引类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获得这些订阅者的信息速度要快。
在Eventbus的demo(EventBusPerformance)中,build->generated->source->apt中我们可以找到MyEventBusIndex索引类,我们对它进行分析一下:
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscriberClassEventBusAsync.class,
true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventAsync", TestEvent.class, ThreadMode.ASYNC),
}));
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscribeClassEventBusMain.class,
true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventMainThread", TestEvent.class, ThreadMode.MAIN),
}));
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscribeClassEventBusBackground.class,
true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventBackgroundThread", TestEvent.class, ThreadMode.BACKGROUND),
}));
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscribeClassEventBusMainOrdered.class,
true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEvent", TestEvent.class, ThreadMode.MAIN_ORDERED),
}));
putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.SubscribeClassEventBusDefault.class,
true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEvent", TestEvent.class),
}));
putIndex(new SimpleSubscriberInfo(TestRunnerActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventMainThread", TestFinishedEvent.class, ThreadMode.MAIN),
}));
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
SUBSCRIBER_INDEX :订阅者对应订阅者信息的map集合
SubscriberInfo:注解器生成的接口
/** Base class for generated index classes created by annotation processing. */
public interface SubscriberInfo {
Class<?> getSubscriberClass();
//获取订阅者类
SubscriberMethod[] getSubscriberMethods();
//获取订阅方法数组
SubscriberInfo getSuperSubscriberInfo();
//获取父类订阅信息
boolean shouldCheckSuperclass();
//是否检查父类
}
具体实现如下:
/** Base class for generated subscriber meta info classes created by annotation processing. */
public abstract class AbstractSubscriberInfo implements SubscriberInfo {
private final Class subscriberClass;
private final Class<? extends SubscriberInfo> superSubscriberInfoClass;
private final boolean shouldCheckSuperclass;
protected AbstractSubscriberInfo(Class subscriberClass, Class<? extends SubscriberInfo> superSubscriberInfoClass,
boolean shouldCheckSuperclass) {
this.subscriberClass = subscriberClass;
this.superSubscriberInfoClass = superSubscriberInfoClass;
this.shouldCheckSuperclass = shouldCheckSuperclass;
}
@Override
public Class getSubscriberClass() {
return subscriberClass;
}
@Override
public SubscriberInfo getSuperSubscriberInfo() {
if(superSubscriberInfoClass == null) {
return null;
}
try {
return superSubscriberInfoClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean shouldCheckSuperclass() {
return shouldCheckSuperclass;
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType) {
return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false);
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode) {
return createSubscriberMethod(methodName, eventType, threadMode, 0, false);
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
int priority, boolean sticky) {
try {
//实际上仍是通过反射获取定义的相关参数,然后生成订阅方法SubscriberMethod,只不过这是在编译时就生成了
Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
} catch (NoSuchMethodException e) {
throw new EventBusException("Could not find subscriber method in " + subscriberClass +
". Maybe a missing ProGuard rule?", e);
}
}
}
public class SimpleSubscriberInfo extends AbstractSubscriberInfo {
private final SubscriberMethodInfo[] methodInfos;
public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) {
super(subscriberClass, null, shouldCheckSuperclass);
this.methodInfos = methodInfos;
}
@Override
public synchronized SubscriberMethod[] getSubscriberMethods() {
//根据抽象父类的反射方法生成订阅方法对象SubscriberMethod
//返回所有的订阅方法
int length = methodInfos.length;
SubscriberMethod[] methods = new SubscriberMethod[length];
for (int i = 0; i < length; i++) {
SubscriberMethodInfo info = methodInfos[i];
methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
info.priority, info.sticky);
}
return methods;
}
}
到这里,我们已经知道索引的具体含义,包括索引怎么生成订阅方法的底层逻辑,接下来我们继续回到通过索引获取订阅方法的上层函数:findUsingInfo(Class<?> subscriberClass)
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获取订阅者信息,下面会分析getSubscriberInfo(findState)
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
//生成订阅方法数组,具体逻辑前面已分析
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
//校验订阅方法
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
//把订阅方法添加到findState的subscriberMethods集合进行保存
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//根据索引获取不到订阅者信息,则通过反射获取
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
分析获取订阅者信息getSubscriberInfo(findState)
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
//获取父类的订阅信息并返回
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
//根据订阅类class,查找对应的索引类,找到后再通过索引类维护的Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX
//返回对应的订阅信息
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
至此,我们已经分析完获取订阅方法的详细逻辑,包括使用反射获取和索引获取。接下来继续分析找到全部订阅方法后,注册流程的下一步subscribe()方法的实现。
3.2.2 subscribe(Object subscriber, SubscriberMethod subscriberMethod)
// Must be called in synchronized block 必须在同步代码块里调用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//根据事件类型获取所有订阅该事件的Subscription集合,Subscription包括订阅者和订阅方法
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
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);
}
}
//根据优先级插入对应的位置
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;
}
}
//将订阅者与对应的订阅事件存放到Map<Object, List<Class<?>>> typesBySubscriber;
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();
//遍历粘性sticky事件
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
// 判断eventType是否为candidateEventType,或者是candidateEventType的父类
if (eventType.isAssignableFrom(candidateEventType)) {
// 得到eventType的子类和eventType 对应的事件
Object stickyEvent = entry.getValue();
//// 立即发送粘性事件到订阅者newSubscription
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
//不是事件继承的,则直接发送粘性事件
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
到这里已经完成register()注册流程的全部解析,流程图(引用自EventBus 3.0 源码分析)如下