深入源码理解EventBus3.0

馋奶兔 提交于 2019-12-02 15:22:06

深入源码理解EventBus3.0

高效使用EventBus3.0

如果要使用EventBus,主要由五步构成,EventBus官方仓库

  1. 添加依赖:

    implementation 'org.greenrobot:eventbus:3.1.1'
    
  2. 定义events事件:

    public static class MessageEvent { /* Additional fields if needed */ }
    

Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:

  1. 准备订阅消息:定义方法名,添加注解,比如要在主线程,是sticky消息

    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {/* Do something */};
    
  2. 注册和解注册订阅者

     @Override
     public void onStart() {
         super.onStart();
         EventBus.getDefault().register(this);
     }
    
     @Override
     public void onStop() {
         super.onStop();
         EventBus.getDefault().unregister(this);
     }
    
  3. 最后,发送订阅消息events:

    EventBus.getDefault().post(new MessageEvent());
    

如果要使用EventBus3.0的新特性EventBusAnnotationProcessor,需要多做三步,可以参考EventBuses官方文档Subscriber Index使用
不了解EventBusAnnotationProcessor,可以看下这篇文章解析EventBusAnnotationProcessor

  1. 在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'
    }
    
  2. 在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);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!