EventBus 的源码分析

EventBus 简化了程序内各个组件之间进行通信的复杂度,极大的解耦了各个模块之间的关联,比如想在 Activity B页面发送个数据给 Activity A页面,我们就可以用它来实现。先定义一个包装数据的bean

Bean

public class MessageEvent {
    public final String message;

    public MessageEvent(String message) {
        this.message = message;
    }
}

Activity  A

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
    }

    @Subscribe
    public void getEventBus(MessageEvent event) {
        if (event != null) {
            //这里拿到事件之后吐司一下
            Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }


Activity B

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact);
        EventBus.getDefault().post(new MessageEvent("Hello World!"));
    }

这样,先启动A页面,跳转到B页面时,就会发送一条信息,A页面 getEventBus() 方法就会接受到,然后弹出吐司。我们来看看里面的实现原理,先看 EventBus.getDefault().register(this)  方法,EventBus 是个单利模式

    static volatile EventBus defaultInstance;

    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

register(this) 方法是注册订阅,把当前对象出入 EventBus 中

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

这里注意了,获取传入对象的 class 信息,然后传入了 SubscriberMethodFinder 中,我们看看这个方法

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        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");
        } else {
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

其实,这个方法中的核心是中间的那段代码,不论是 findUsingReflection(subscriberClass) 还是findUsingInfo(subscriberClass),对于我们来说,都会执行一些相同的逻辑,这里以 findUsingReflection() 方法为例,讲一下

    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

prepareFindState() 是创建 FindState 对象,先去缓存中找,如果没有,就创建;initForSubscriber(subscriberClass) 是用来初始化 FindState 信息;重点来了,看看 while 循环中的两个方法 findUsingReflectionInSingleClass(findState) 和 findState.moveToSuperclass(),先看第一个

    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();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                    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)) {
                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.clazz.getDeclaredMethods() 获取到 class 文件本身的方法,如果异常了,就也获取它父类中的方法,然后遍历获取的方法,首先会获取方法的权限等信息,必须是 public 修饰的,下一步就是获取方法中参数的个数,if (parameterTypes.length == 1) 意思是方法中形参的个数必须是一个,Subscribe subscribeAnnotation =method. getAnnotation( Subscribe.class); 这个是用到了注解,对应上面例子中 getEventBus() 方法上面的注解 @Subscribe(不了解注解的可以补充一下相关知识再继续往下看),这里根据方法上面是否有注解来判断出我们注册的方法,这样就能从一堆方法中迅速找到我们需要的方法,效率比较高。Class<?> eventType = parameterTypes[0] 获取的是我们定义的方法中参数的class类型; findState.checkAdd(method, eventType) 是用来校验它是否需要添加到集合中

    boolean checkAdd(Method method, Class<?> eventType) {
        Object existing = anyMethodByEventType.put(eventType, method);
        if (existing == null) {
            return true;
        } else {
            if (existing instanceof Method) {
                if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                    // Paranoia check
                    throw new IllegalStateException();
                }
                // Put any non-Method object to "consume" the existing Method
                anyMethodByEventType.put(eventType, this);
            }
            return checkAddWithMethodSignature(method, eventType);
        }
    }

比如像 Activity A 中,只有一个方法,刚进来就 return true,但如果它也有父类,父类中也有注册的回调方法,那么就会走到下面的判断,看看 checkAddWithMethodSignature() 方法

    private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
        methodKeyBuilder.setLength(0);
        methodKeyBuilder.append(method.getName());
        methodKeyBuilder.append('>').append(eventType.getName());

        String methodKey = methodKeyBuilder.toString();
        Class<?> methodClass = method.getDeclaringClass();
        Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
        if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
            return true;
        } else {
            subscriberClassByMethodKey.put(methodKey, methodClassOld);
            return false;
        }
    }

methodClassOld == null 意味着第一次调用,isAssignableFrom() 意思是 methodClassOld 是否是 methodClass 的父类或者是同一个类,如果满足这两个条件中任意一个,则返回 true,当该方法返回 true 时,checkAdd() 返回值也为 true。

重新看回 findUsingReflectionInSingleClass() 方法,findState.checkAdd(method, eventType) 中返回true时,会把 方法名method、参数类型 eventType 以及 ThreadMode的值默认是枚举类型 POSTING 封装到 SubscriberMethod 对象中,然后添加到 FindState 对象中 subscriberMethods 集合中,到此 findUsingReflectionInSingleClass(findState) 分析完毕,继续看 findUsingReflection() 中 while 循环中年的第二个方法 findState.moveToSuperclass()

    void moveToSuperclass() {
        if (skipSuperClasses) {
            clazz = null;
        } else {
            clazz = clazz.getSuperclass();
            String clazzName = clazz.getName();
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                clazz = null;
            }
        }
    }


这个方法的意思就是把 clazz 的父类值赋值给 clazz; findUsingReflectionInSingleClass() 方法中 clazz.getDeclaredMethods() 获取异常时会调用 getMethods() 方法,同时把 skipSuperClasses 属性置为 true,意思是现在已经是在父类了,moveToSuperclass() 中第一行的判断意思就没必要再次找它的父类了。

findUsingReflection() 中最后一个方法 getMethodsAndRelease() 是把 FindState 对象信息清除,然后回收放到数组中,便于下次复用。 到此,subscriberMethodFinder.findSubscriberMethods(subscriberClass)方法中获取的对象是个集合,里面是 SubscriberMethod 对象,对象中封装了注册的方法名和方法形参的类型,我们继续看 register() 方法中的增强for循环 subscribe() 方法

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        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;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        ...
    }

方法中简化了一些代码,这个方法看着代码挺长的,其实重点就那么几行,其他的都是为了复用做的优化。把 subscriber 和 subscriberMethod 这两个对象封装到 Subscription 中,然后添加到集合中,然后以形参类型为key值,这个list集合为 value,添加到 subscriptionsByEventType 这个map集合中;往下看,首次 for 循环中 i 为 0 时, subscriptions 集合中也没有对象,把 newSubscription 对象添加进去;再往下看,一个套路,把形参类型添加到 subscribedEvents 中,再次添加到 typesBySubscriber 集合中。

EventBus.getDefault().register(this) 注册的这个方法就讲完了,通过反射和注解找到注册对象的相关的方法,然后把方法和注册对象及方法形参类型等封装到对象中,然后添加到集合中缓存起来,等待使用。下面看看 EventBus.getDefault().post(new MessageEvent("Hello everyone!")) 里面的源码

    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

这个方法中,把要发送的对象 event 添加到 eventQueue 集合中,然后加些逻辑判断,比如同一个只执行一次,是否在UI线程,最后是调用 postSingleEvent() 方法

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

lookupAllEventTypes(eventClass) 方法意思是获取对象 event 及其父类的信息的集合,这里event只是默认的继承了 Object,所以集合中有两个对象,在上文例子中 eventTypes 是 [...MessageEvent, class java.lang.Object],接下来看看 postSingleEventForEventType() 方法

    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 {
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }


重点只有一行 postToSubscription(subscription, event, postingState.isMainThread) ,注意是 for 循环的,其他的可以忽略不计

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            ...
        }
    }

    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);
        }
    }

subscription.subscriberMethod.method 就是我们注册的方法 getEventBus(MessageEvent event),subscription.subscriber 是 Activity A,event 是 Activity B 中的 new MessageEvent("Hello everyone!") 对象,很明显,这里是个反射,调用了 Activity A 中的方法。

至于最后 EventBus.getDefault().unregister(this) 解绑这个里面,代码比较简单,移除引用,这里不再多说。
 

发布了176 篇原创文章 · 获赞 11 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Deaht_Huimie/article/details/102554420