EventBus源码分析

最近感觉遇到了瓶颈,简单的东西不想做,难的东西做不出来,比如设计模式,设计思想,框架搭建等,这些自己虽然能看懂,也会用,但是到了实际工作中,就懵了,所以想通过分析一些框架的源码来加强这部分的弱点和痛处,希望之后回过头来能感觉自己学到很多东西。

现在就EventBus这个开源项目进行分析,目前已更新到3.1.1.网上有很多分析的文章,比较全面的是这一篇EventBus源码分析,我也略作参考,但是自己打算对于各个细节和写的比较好的地方都说明一下,所以篇幅可能会很长,内容也会分多篇,由于工作,也可能需要耗费较长的时间来分析,每周更新吧。就这样,开始了。

   github地址:https://github.com/greenrobot/EventBus

   先放一张官方流程图和介绍:

 

EventBus: Events for Android

EventBus is an open-source library for Android and Java using the publisher/subscriber pattern for loose coupling. EventBus enables central communication to decoupled classes with just a few lines of code – simplifying the code, removing dependencies, and speeding up app development.
EventBus-Android-Publish-Subscribe

    

翻译下:EventBus是一个用于Android和Java的开源库,使用发布/订阅模式实现松耦合,EventBus允许中央通信只需几行代码就可以解耦类——简化代码,消除依赖,并且增加应用程序开发速度。

流程图分析:订阅者关联到EventBus,存储下来,也就是resgister.发布者发送消息的时候,将事件发送到EventBus,再由EventBus分发到订阅者,订阅者通过onEvent()方法来接受到消息,从而处理数据。

//todo

首先分析EventBus.getDefault().register(this)这个方法。

  

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

看第3行的方法,findSubscriberMethods()这个是从方法缓存队列里取到当前这个类的反射方法。

SubscriberMethod :是反射方法类,包含优先级,具体方法,响应事件等。

SubscriberMethodFinder:反射方法查询器

再看看findSubscriberMethods()这个方法的具体实现

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

这个方法首先从缓存中取类的方法集合,如果有,直接返回,否则通过反射或者类信息去查找。

如果2种方式都没有找到,则说明没有定义一个@Subscribe的注解方法,或者定义的方法有问题.走到下面判空时就会抛出异常.

比如下面这种,方法中带有2个参数:

@Subscribe
    public void onEventMainThread(EventInfo eventInfo,String msg) {
        Log.d("Event", eventInfo.getName());
    }

 如果找到了注解的方法,则添加进缓存,添加方式key=类,value=注解的方法.

优点:METHOD_CHCHE是一个ConcurrentHashMap,它是支持并发和线程安全的,这里因为读取次数可能较多,用这个集合比HashMap来说要安全高效.

ignoreGeneratedIndex这个boolean是强制调用反射,目前赋值的地方还没有找到,这个变量属于EventBusBuilder里的一个属性.

  接下来分析findUsingReflection()这个方法,

 private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();//准备查询标记
        findState.initForSubscriber(subscriberClass);//初始化订阅者
        while (findState.clazz != null) {//遍历所有的方法
            findUsingReflectionInSingleClass(findState);//开始反射
            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
            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();//获取注解方法的类型,private还是 public
            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");
            }
        }
    }

  使用过EventBus的coder应该知道EventBus规定注解的方法必须是public并且方法上所带的参数仅有且必须有一个,这个方法就是其实现.通过method.getModifiers()获取其属性,如果不是public的方法,则抛出EventBusException异常.异常里的英文已经说的很明确了,必须是public,不能加static,abstract.

 然后通过method.getParameterTypes();获取到注解方法的参数数量,如果没有参数或者参数在一个以上。也会抛出异常.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值