可用于应用内的消息事件传递, 方便快捷, 耦合性低
1. 基本用法
- public class EventBusMain extends AppCompatActivity {
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.content_main);
- EventBus.getDefault().register(this);
- }
- 订阅的事件 onEvent1
- @Subscribe
- public void onEvent1(RemindBean bean){
- }
- 订阅的事件 onEvent2
- @Subscribe
- public void onEvent2(UserInfo bean){
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- EventBus.getDefault().unregister(this);
- }
- }
需要发送消息传递的时候:
EventBus.getDefault().post(new RemindBean())
2. 源码解读
放上官网的一张原理图, 感觉挺清晰的:
发布消息的一方(Publisher), 只需要 post 一个 event 之后就不用管了, EventBus 内部会将 event 逐一分发给订阅此 event 的订阅者(Subscriber). 不错就是这样一个东西.
还记得以往我要实现两个不同的 activity 之间要传递一些数据的时候, 我都是通过定义一个 interface 的形式完成, 时间一长, 定义的接口一堆, 在回顾查看代码也确实不够美观. 好了话不多说, 看下大家都在用的 Eventbus.
3. 首先
EventBus.getDefault().register(this);
getDefault():
EventBus 是一个单例模式, 懒汉式, 双重判断
- /** 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;
- }
register 是什么意思呢, 就是就跟你订阅报纸一样, 报社需要确定几个重要的问题:
订阅者是谁(Subscriber)?
订阅的什么报纸(Event) ?
就是我认为比较重要的, 那么 register 这一步就是 Subscriber 告诉 报社, 订阅的 event
public void register(Object subscriber) {
- 1. 先拿到这个订阅者 (subscriber) 类的字节码
Class<?> subscriberClass = subscriber.getClass();
- 2. 通过这个类的字节码, 拿到所有的订阅的 event, 存放在 List 中
- List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
- synchronized (this) {
- 3. 循环遍历所有的订阅的方法, 完成 subscriber 和 subscriberMethod 的关联
- for (SubscriberMethod subscriberMethod : subscriberMethods) {
- subscribe(subscriber, subscriberMethod);
- }
- }
- }
我们看下这个如何根据 subscriberClass 找到这个订阅的 method 的, findSubscriberMethods:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
- 1. 先从缓存中取
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
- 2. 第一次肯定 null
- if (subscriberMethods != null) {
- return subscriberMethods;
- }
- 3. 查找默认也是 false, 感兴趣的可以看下
- if (ignoreGeneratedIndex) {
- subscriberMethods = findUsingReflection(subscriberClass);
- } else {
- 4. 所以是走这里
- subscriberMethods = findUsingInfo(subscriberClass);
- }
- if (subscriberMethods.isEmpty()) {
- throw new EventBusException("Subscriber" + subscriberClass
- + "and its super classes have no public methods with the @Subscribe annotation");
- } else {
- 5. 找到之后添加到缓存中, key 是 subscriber ;value 是: methods
- METHOD_CACHE.put(subscriberClass, subscriberMethods);
- return subscriberMethods;
- }
- }
看下: findUsingInfo(subscriberClass)
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
- 1. 我认为就是准备一个查找结果得存储对象
FindState findState = prepareFindState();
- 2. 将订阅者的 subscriberClass 存储起来, 保存在一个 FindState 类中的 subscriberClass
同时赋值给 clazz 变量中, 以下代码能够看出
- // void initForSubscriber(Class<?> subscriberClass) {
- // this.subscriberClass = clazz = subscriberClass;
- //}
- findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {进入循环中
- // 获取 subscriberInfo 信息, 返回 null
- 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.add(subscriberMethod);
- }
- }
- } else {
- 3. 进入到这里了
- findUsingReflectionInSingleClass(findState);
- }
- 4. 查找父类中的方法
- findState.moveToSuperclass();
- }
- return getMethodsAndRelease(findState);
- }
findUsingReflectionInSingleClass 如下:
- private void findUsingReflectionInSingleClass(FindState findState) {
- Method[] methods;
- try {
- // This is faster than getMethods, especially when subscribers are fat classes like Activities
- 1. 通过订阅者的字节码查找当前类中所有生命的方法
- 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;
- }
- 2. 循环遍历所有的方法
for (Method method : methods) {
- 3. 获取方法的修饰符
int modifiers = method.getModifiers();
- 4. 判断修饰符, 订阅方法的修饰符不能是 private,static
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
- 5. 获取方法的所有的参数
Class<?>[] parameterTypes = method.getParameterTypes();
- 6. 判断参数的个数, 只能有 1 个参数, 订阅方法中
if (parameterTypes.length == 1) {
- 7. 获取方法上具有 subscribe 注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
- 8. 含有 subscribe 注解的方法, 就是该类订阅的方法, 其它不符合的可能就是普通的方法
if (subscribeAnnotation != null) {
- 9. 获取第一个参数 eventType
- Class<?> eventType = parameterTypes[0];
- if (findState.checkAdd(method, eventType)) {
- 10. 获取注解的 mode, 就是我们在注解上标识的,
有 mainThread,Posting,background,async
ThreadMode threadMode = subscribeAnnotation.threadMode();
- 11. 将订阅方法的一系列信息 (方法名称, threadMode, 优先级, 是否是粘性等) 添加到集合 subscriberMethods 中去
- findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
- subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
- }
- }
- } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
- 12. 参数是多个的时候抛出异常
- 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)) {
- 13. 方法的修饰符不是 public 的, 抛出异常
- 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 类中去了. 再回头看我们原先那个方法, 到第三步了:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
- 1. 我认为就是准备一个查找结果得存储对象
FindState findState = prepareFindState();
- 2. 将订阅者的 subscriberClass 存储起来, 保存在一个 FindState 类中的 subscriberClass
同时赋值给 clazz 变量中, 以下代码能够看出
- // void initForSubscriber(Class<?> subscriberClass) {
- // this.subscriberClass = clazz = subscriberClass;
- //}
- findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {进入循环中
- // 获取 subscriberInfo 信息, 返回 null
- 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.add(subscriberMethod);
- }
- }
- } else {
- 3. 进入到这里了, 上面已经分析所有信息保存到 findState 中
- findUsingReflectionInSingleClass(findState);
- }
- 4. 查找父类中的方法
- findState.moveToSuperclass();
- }
- return getMethodsAndRelease(findState);
- }
在这个 getMethodsAndRelease(findState):
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
- 1. 取出里面的 subscriberMethods
- List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
- findState.recycle();
- synchronized (FIND_STATE_POOL) {
- for (int i = 0; i <POOL_SIZE; i++) {
- if (FIND_STATE_POOL[i] == null) {
- FIND_STATE_POOL[i] = findState;
- break;
- }
- }
- }
- 2. 返回集合
- return subscriberMethods;
- }
至此, 我们知道了根据订阅者 (subscriber) 的 clazz 找到了所有订阅的方法事件 methods
回到最初的第一步 register:
- public void register(Object subscriber) {
- Class<?> subscriberClass = subscriber.getClass();
- 2. 完成
- List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
- synchronized (this) {
- for (SubscriberMethod subscriberMethod : subscriberMethods) {
- 3. 循环遍历所有的订阅方法和订阅者之间建立关联
- subscribe(subscriber, subscriberMethod);
- }
- }
- }
subscribe(subscriber, subscriberMethod) 方法:
- // Must be called in synchronized block
- private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
- 1. 订阅方法的 eventType 的字节码
Class<?> eventType = subscriberMethod.eventType;
- 2. 订阅者和订阅方法封装成一个 Subscription 对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
- 3. subscriptionsByEventType 第一次也是 null , 根据 eventType
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
- 4. 第一次肯定为 null
- if (subscriptions == null) {
- subscriptions = new CopyOnWriteArrayList<>();
- 5. key 为 eventType, value 是 subscriptions 对象
- subscriptionsByEventType.put(eventType, subscriptions);
- } else {
- 抛出异常
- if (subscriptions.contains(newSubscription)) {
- throw new EventBusException("Subscriber" + subscriber.getClass() + "already registered to event"
- + eventType);
- }
- }
- 6. 获取所有添加的 subscriptions
- int size = subscriptions.size();
- for (int i = 0; i <= size; i++) {
- 7. 会判断每个订阅方法的优先级, 添加到这个 subscriptions 中, 按照优先级
- if (i == size || subscriberMethod.priority> subscriptions.get(i).subscriberMethod.priority) {
- subscriptions.add(i, newSubscription);
- break;
- }
- }
- 8. 获取订阅的方法集合
- List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
- if (subscribedEvents == null) {
- subscribedEvents = new ArrayList<>();
- 9. 为空添加到 typesBySubscriber
- typesBySubscriber.put(subscriber, subscribedEvents);
- }
- 10. 订阅事件添加到 subscribedEvents 集合中去
subscribedEvents.add(eventType);
- 11. 判断是否是粘性事件的关联
- 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();
- 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);
- }
- }
- }
到此, 如果你跟着我一步步看到这里, 应该大概明白一些了, 还有一部分没完, 就是 register 前半部分完成订阅, 存储等工作; 剩下 post(event) 方法就是将 event 分发给相应订阅过此事件的订阅者了.
来源: https://juejin.im/post/5bb021f46fb9a05d0e2e7468