深入源码理解EventBus3.0
高效使用EventBus3.0
如果要使用EventBus,主要由五步构成,EventBus官方仓库
-
添加依赖:
implementation 'org.greenrobot:eventbus:3.1.1'
-
定义events事件:
public static class MessageEvent { /* Additional fields if needed */ }
Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:
-
准备订阅消息:定义方法名,添加注解,比如要在主线程,是sticky消息
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* Do something */};
-
注册和解注册订阅者
@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); }
-
最后,发送订阅消息events:
EventBus.getDefault().post(new MessageEvent());
如果要使用EventBus3.0的新特性EventBusAnnotationProcessor,需要多做三步,可以参考EventBuses官方文档Subscriber Index使用
不了解EventBusAnnotationProcessor,可以看下这篇文章解析EventBusAnnotationProcessor
-
在app的build.gradle中添加如下配置
android { defaultConfig { javaCompileOptions { annotationProcessorOptions { // 配置参数名和值 arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ] } } } } dependencies { implementation 'org.greenrobot:eventbus:3.1.1' annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1' }
-
在Application初始化的时候,也就是在Application.onCreate()里面,这样调用
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus(); // Now the default instance uses the given index. Use it like this: // 以后就可以通过EventBus.getDefault(),获取EventBus EventBus eventBus = EventBus.getDefault();
完成以上几步后,重新编译一次,就可以在app/build/generated/source/apt/debug/目录下看到生成的MyEventBusIndex类,下面是我的示例中生成的代码:
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onTestEvent", MainActivity.TestEvent.class, ThreadMode.MAIN, 0, true),
}));
}
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;
}
}
}
需要注意的一点是,项目中至少要有一个订阅信息,否则EventBusProcessor获取到的订阅信息为空,就不会生成相应的MyEventBusIndex类了。
源码解析EventBus3.0
接下来已不复从源码解析EventBus到底是如何实现订阅的
首先看一下是如何一步步实现注册订阅消息,注册和消息类都在下面
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onTestEvent(TestEvent event) {
Log.d("EventDebug", "onTestEvent get event");
}
在MainActivity里面onCreate调用,EventBus.getDefault().register(this),来实现注册订阅消息;在onDestroy调用unregister,解注册订阅消息。
register和unregister必须成对出现,不然会造成内存泄漏。因为EventBus在register的时候,会把当前类的实例存在一个EventBus单例的一个内存实例subscriptionsByEventType当中
注册订阅消息
public void register(Object subscriber) {
// subscriberClass是注册订阅消息的类,EventBus.getDefault().register(this),如其中传入的this,也就是com.test.eventbussample.MainActivity
Class<?> subscriberClass = subscriber.getClass();
// 找到需要注册的方法和注册的消息事件
// subscriberMethods是注册订阅消息的方法,如MainActivity中的onEvent(TestEvent event)方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 把所有的信息保存到subscriptionsByEventType等中
subscribe(subscriber, subscriberMethod);
}
}
}
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 缓存过该类(该类已经注册过一次),直接取缓存
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// ignoreGeneratedIndex默认为false,因为反射成本高
if (ignoreGeneratedIndex) {
// 用反射的方式查找
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// EventBus3.0新增特性,用EventBusAnnotationProcessor,注解处理工具实现
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
// 把找到的缓存入METHOD_CACHE里面,下次注册可以直接取出,不用再查找
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
findUsingInfo()具体实现
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// 初始化FindState
FindState findState = prepareFindState();
// 把FindState和订阅类subscriberClass关联
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 找到所有订阅类subscriberClass的订阅方法
findState.subscriberInfo = getSubscriberInfo(findState);
// 如果通过subscriberInfoIndexes找到了当前订阅类的信息,就直接添加到findState中
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 {
// 如果通过subscriberInfoIndexes没找到当前订阅类的信息,还是需要通过反射去查找
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
getSubscriberInfo找到所有订阅类subscriberClass的订阅方法
private SubscriberInfo getSubscriberInfo(FindState findState) {
// 因为findState实例是在缓存池里复用的,所以先查看当前上一个实例的订阅类clazz和当前的订阅类getSubscriberClass是否一样,如果一样就直接返回结果,因为已经查找过一次。
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
// subscriberInfoIndexes,通过EventBusAnnotationProcessor注解处理工具保存的所有订阅了消息的类和对应方法
// 查找subscriberInfoIndexes中有没有当前订阅类subscriberClass的相关订阅信息
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
通过反射查找订阅类subscriberClass的所有订阅的方法
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
// 同样初始化FindState
FindState findState = prepareFindState();
// 再把FindState和订阅类subscriberClass关联
findState.initForSubscriber(subscriberClass);
// 采用while循环,查找所有当前类的父类是否存在订阅的方法
while (findState.clazz != null) {
// 实际通过反射找订阅类subscriberClass的所有订阅的方法
findUsingReflectionInSingleClass(findState);
// 切换到当前类的父类
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
moveToSuperclass,切换到当前类的父类
void moveToSuperclass() {
// 默认skipSuperClasses = false,需要循环遍历父类是否有订阅方法
if (skipSuperClasses) {
clazz = null;
} else {
// 获取父类calss
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
// 跳过所有的系统class类,提高检索性能
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
findUsingReflectionInSingleClass,实际通过反射找订阅类subscriberClass的所有订阅的方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
// 通过反射找到所有订阅类subscriberClass含有方法(getDeclaredMethods可以当前类的所有方法,包括private,protected,public,但是不能找到继承自父类的方法)
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的,不是的话不会加入注册成功,所以订阅的方法必须是public的
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
// 获取订阅类subscriberClass的注解信息,主要是获取sticky,threadMode,priority信息
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
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)) {
/** strictMethodVerification Enables strict method verification (default: false). */
// strictMethodVerification 参数主要是是否严格验证,默认是false的,如果为true,会严格验证是否是public方法,如果不是public方法,会直接抛出EventBusException异常
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
发送和接收订阅消息
public void post(Object event) {
// currentPostingThreadState是通过ThreadLocal来存储的,每一个线程一个实例
// 获取当前线程的postingState,并把当前的消息存入当前线程的队列中
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
// 不断循环post,当前线程队列eventQueue里面的消息event
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
postSingleEvent单条消息
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// 默认eventInheritance = true,TestEvent可能是一个继承类,所以需要判断所有的父类,然后也需要post所有的父类消息
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// postSingleEventForEventType,执行post当前消息类clazz(可能是eventClass,也可能是eventClass的父类或者继承的接口)
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
// postSingleEventForEventType,直接执行post当前消息类eventClass
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
// 如果没有在找到当前消息的订阅者,容错处理
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
postSingleEventForEventType,执行post消息类eventClass
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 {
// 真正把消息post出去
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
// 把postingState重置
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
// 真正把消息post出去,根据不同的线程,执行不同的方法
// isMainThread: post的线程是否是主线程
// subscription.subscriberMethod.threadMode:订阅者是否要在主线程执行
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
// 通过反射方法,真正通知订阅者
invokeSubscriber(subscription, event);
break;
case MAIN:
// post的线程是否是主线程,如果是直接执行
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
// 否则加入到主线程队里
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
// 主线程是否需要按序执行,如果是加入到主线程队里
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// 否则,直接执行
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
// post的线程是否是主线程,如果是加入到backgroud队列里
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);
}
}
通过反射方法,真正通知订阅者。如反射执行MainActivity的onTestEvent(TestEvent event)方法
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
如果post的线程和订阅者的线程不同,会先equeue到poster里面,来看下equeue具体做了什么吧
如下是AsyncPoster的equeue方法,先把消息enqueue进了pendingPost里面,然后在异步线程executorService里面直接运行run方法
在run方法里面调用eventBus的invokeSubscriber()方法,通过反射方法,真正通知订阅者
HandlerPoster和BackgroundPoster和AsyncPoster也是类似,只不过他们因为消息更多,为了不频繁切换线程,加了循环会更复杂些;HandlerPoster还加了handler里面运行时间长短,来判断是否要循环执行队列消息,还是post出去,主要是为了防止不断循环执行equeue里面的消息卡死主线程,所以post出去和系统Handler里面的消息竞争
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
发送和接收订阅粘性消息(sticky = true)
poststicky作用:指事件消费者在事件发布之后才注册的也能接收到该事件
发送一个粘性消息
EventBus.getDefault().postSticky(new TestEvent());
看下postSticky里面到底做了什么
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
只是把event事件存在了stickyEvents里面而已,其他的和非sticky事件做的操作相同,post消息出去。
接下来看下stickyEvents具体在什么时候发挥作用的,原来是在注册的时候,保存信息时调用的subscribe()里.
如果是订阅的事件sticky = true,就去遍历sticky事件,然后在订阅的时候,就通知了订阅者粘性事件
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
...
// 都是保存订阅消息的
// 如果订阅的是粘性事件,sticky = true
if (subscriberMethod.sticky) {
// 是否需要判断stickyEvent的父类和接口
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();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// 判断非空,然后和非粘性消息一样,post消息
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
做到极致的缓存池复用
缓存池中的实例复用做到的极致,在易重复创建对象的地方都采用了缓存池,复用对象。
在找订阅类subscriberClass的订阅方法的时候,复用了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();
}
在发送消息的时候复用了PendingPost
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
来源:https://blog.csdn.net/qq_16927853/article/details/102779244