EventBus 源码解析(3.1.1 初步)

 

 

eventbus 一个比较著名的开源库,使用方便,很多项目都在使用。

但是我们没有使用这个库,我们在相同的业务场景下一般都是使用的观察者模式,个人感觉使用后,会影响代码的可读性。虽然我们没有使用Event,但是发现好多公司的面试都在考这个库的原理,所以,打算自己初步的分析下源码。

我习惯按照使用步骤来分析,如下:

一  使用步骤

先说下eventbus怎么使用的吧。

1. 注册

EventBus.getDefault().register(this);

2.发送消息

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

3.反注册

EventBus.getDefault().unregister(this);

二 源码分析

1.注册

注册主要完成的工作是解析订阅者中所有的订阅方法(包含Subscribe),然后以方法参数类型为键,方法列表为值保存起来。接下来看代码分析:

 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);  //找到订阅的方法
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);   //将订阅的方法和订阅者绑定
            }
        }
    }

                                                                                         代码片段1

注册的流程主要关注俩个地方,findSubscriberMethods和subscribe方法;

findSubscriberMethods方法,会找到订阅者subscriber中所有的订阅方法(被Subscribe注解的方法):

  List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);  //从缓存中获取 Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
        if (subscriberMethods != null) {
            return subscriberMethods;   //如果从缓存中拿到了就返回
        }

        if (ignoreGeneratedIndex) {  //默认为false
            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;
        }
    }

                                                                                            代码片段2

我们一般都是使用反射来获取的,所以看反射获取的方法findUsingReflection:

private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();  //拿到方法信息的包装类
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {  //遍历subscriberClass的父类,去拿所有的订阅方法
            findUsingReflectionInSingleClass(findState);  //反射获取订阅方法
            findState.moveToSuperclass();  //里面有findstate.clazz = findstate.clazz.getSuperclass();将当前对象指向父类,继续执行,直到类名开头的是,java,javax,android
        }
        return getMethodsAndRelease(findState);
    }

                                                                                             代码片段3

接下来再看下findUsingReflectionInSingleClass方法:

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();  //看注释,getDeclaredMethods方法比getMethods在臃肿的activity中快。
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;  //getDeclaredMethods是获取当前类的所有方法,而getMethods是获取当前类包括其父类的所有方法,所以这里就不用去父类中找了。
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //方法必须是公有方法,并且不包含abstaract,static等修饰符
                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");
            }
        }
    }

                                                                                       代码片段4

MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;

通过反射拿到订阅者的所有方法。然后遍历所有方法,找到被Subscribe.class注解过的方法,并且要求该方法参数只有一个,修饰符必须是public并且不能有static,abstract。在来看下checkAdd方法做了什么:

   boolean checkAdd(Method method, Class<?> eventType) {
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type.
            Object existing = anyMethodByEventType.put(eventType, method); //检查之前在该参数下是否添加过方法
            if (existing == null) {
                return true;   //如果没有就直接返回
            } else {
                if (existing instanceof Method) {  //如果之前保存的数据类型是method
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) { //对旧的数据进行签名检查,如果不通过抛异常,并将类型保存为Findstate避免下次再执行这个操作
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);  //以键为eventType,值为FindState保存起来
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }

        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)) {  //如果之前没有保存过对应的类,或者在子类没有重写的时候添加(我看代码的时候好像不是这样的,但是注释这么说。。。。。)
                // Only add if not already found in a sub class
                return true;
            } else {
                // Revert the put, old class is further down the class hierarchy
                subscriberClassByMethodKey.put(methodKey, methodClassOld);   //否则,将之前添加过的覆盖掉
                return false;
            }
        }

                                                                                             代码片段5

回到代码片段2,从信息内那使用的方法是findUsingInfo:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass); //同上,准备方法信息,这里面会将subscriberInfo 置为null
        while (findState.clazz != 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 {  //如果没有通过注解拿到的话就通过反射拿(同上)
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

                                                                                            代码片段6

回到之前的subscribe方法:

  // Must be called in synchronized block
    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);

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

                                                                                   代码片段7

2 发送事件

在发送事件的时候回根据事件的类型,找到对应的订阅方法,然后通过反射,并且根据设置的线程类型,调用方法。

  /** Posts the given event to the event bus. */
    public void post(Object event) {
        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()) {  //循环发送事件,直到事件队列为空
                    postSingleEvent(eventQueue.remove(0), postingState);  //发送事件
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

                                                                                           代码片段8

发送的时候会对发送操作也做一个封装,然后会修改一些发送状态,如,是否是主线程,以及正在发送的状态等,发送完后要修改状态,其余的操作注释里有说明。发送操作主要在postSingleEvent方法里:

 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {  //默认为true,标识是否要发送整个事件继承体系的所有类型
            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) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

                                                                                             代码片段9

这个方法主要是处理是否要发送事件的整个继承体系的所有类型,由(eventInheritance) 判断,默认是要发送的。

  private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);  //从订阅者信息集合内拿到数据(添加是在subscribe方法内)
        }
        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;   //如果没有找到对应的订阅者返回false
    }

  private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {   //根据线程类型发送事件
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                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:
                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);
        }
    }

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

                                                                                            代码片段10

最后这部分就很好理解了,根据指定的线程类型和当前所在的线程发送事件。需要注意的是,如果调用post的时候所在的线程是子线程,并且指定的也是子线程的话,会直接执行,并不会重开线程(我之前理解的有误)。

3.反注册

反注册就是将数据移除的过程,比较简单。

   public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);  //根据订阅者知道该订阅者的订阅方法参数类型(在subscribe方法内添加的)
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);  //逐个移除
            }
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

    /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //根据订阅方法,找到保存的订阅信息集合 (在subscribe方法内添加的)
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {  //只移除指定订阅者的数据,因为同一个参数类型的事件可能被多个订阅者注册
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

 

三 自己完成一个简单的eventbus

1.注解实现 和一些包装类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface subscribe {
    ThreadMode threadMode() default ThreadMode.POST;
}
public enum ThreadMode {
    POST,
    MAIN,
    BACKGROUND
}
public class MethodInfo {
    private ThreadMode threadMode;
    private Method method;
    private Object subscriber;
    private Class clazz;

    public MethodInfo(ThreadMode threadMode, Method method,Class clazz,Object subscriber) {
        this.threadMode = threadMode;
        this.method = method;
        this.subscriber = subscriber;
        this.clazz = clazz;
    }

get....
set....

}

2.eventbus主类

public class EventBus {
    private static final EventBus instance = new EventBus();
    private Map<Class, List<MethodInfo>> types = new HashMap<>();  //保存解析出的订阅方法的map
    private Handler handler = new Handler(Looper.getMainLooper());  //主线程handler
    private Executor executor = Executors.newSingleThreadExecutor();  //线程池

    public static EventBus getDefault() {
        return instance;
    }

    public void register(Object o) {
        Class<?> aClass = o.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();  //拿到声明的方法,没有向上拿父类的方法
        if (declaredMethods != null && declaredMethods.length > 0) {
            for (Method declaredMethod : declaredMethods) {
                subscribe annotation = declaredMethod.getAnnotation(subscribe.class);  //拿到方法的注解
                if (annotation != null) {
                    Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
                    if (parameterTypes.length == 1) {   //参数只能为1
                        ThreadMode threadMode = annotation.threadMode();
                        MethodInfo methodInfo = new MethodInfo(threadMode, declaredMethod, parameterTypes[0], o);  //new订阅方法的包装类
                        List<MethodInfo> methodInfos = types.get(parameterTypes[0]);
                        if (methodInfos == null) {
                            methodInfos = new ArrayList<>();
                        }
                        methodInfos.add(methodInfo);
                        types.put(parameterTypes[0], methodInfos);  //以参数类型为键保存
                    }
                }
            }
        }
    }

    public void post(Object o) {
        Class<?> aClass = o.getClass();
        List<MethodInfo> methodInfos = types.get(aClass);  //根据事件类型找到对应的订阅方法集合
        if (methodInfos == null || methodInfos.size() == 0) {
            throw new RuntimeException();
        }
        for (MethodInfo methodInfo : methodInfos) {
            if (methodInfo.getClazz().isAssignableFrom(o.getClass())) {  //如果事件类型和订阅者的类型相同就给这个订阅者发送事件
                postEvent(methodInfo, o);
            }
        }
    }

    private void postEvent(final MethodInfo methodInfo, final Object o) {
        switch (methodInfo.getThreadMode()) {  //根据事件设置的线程类型发送事件
            case POST:
                invokMethod(methodInfo, o);
                break;
            case BACKGROUND:
                if (isMain()) {
                    executor.execute(new Runnable() {
                        @Override
                        public void run() {
                            invokMethod(methodInfo, o);
                        }
                    });
                } else {
                    invokMethod(methodInfo, o);
                }
                break;
            case MAIN:
                if (isMain()) {
                    invokMethod(methodInfo, o);
                } else {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            invokMethod(methodInfo, o);
                        }
                    });
                }
                break;
        }
    }


    public void unregister(Object o) {
        Set<Class> classes = types.keySet();
        Iterator<Class> iterator = classes.iterator();
        while (iterator.hasNext()) {  
            Class next = iterator.next();
            List<MethodInfo> methodInfos = types.get(next);
            for (int i = 0; i < methodInfos.size(); i++) {
                MethodInfo methodInfo = methodInfos.get(i);
                if (methodInfo.getSubscriber().getClass().isAssignableFrom(o.getClass())) {  //根据订阅者的类型删除集合内对应的数据
                    methodInfos.remove(i);
                }
            }
        }

    }

    private void invokMethod(MethodInfo methodInfo, Object o) {
        try {
            methodInfo.getMethod().invoke(methodInfo.getSubscriber(), o);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private boolean isMain() {
        return Looper.getMainLooper() == Looper.myLooper();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值