EventBus原理详解

来源:互联网 发布:多客户端访问数据库 编辑:程序博客网 时间:2024/06/18 07:10

在EventBus 3.0 使用介绍 这篇博客中介绍了关于EventBus的一些使用方法,下面我们就来看看它内部的具体实现吧!

流程图

先来一张整体流程图:

这里写图片描述
这里写图片描述

思路图

在看看register 和 post 的过程思路图:

register

这里写图片描述

post

这里写图片描述

通过上面的几张图,我们可以大致了解eventbus的工作流程,下面我们在来介绍一下这个流程中比较重要的几个方法

重要的方法

register中重要的方法

    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);//使用apt处理器拿到订阅者中的订阅方法        }        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;        }    }

通过反射获取方法

//准备一个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) { //得到一个state并将相应的引用变量置为null                    FIND_STATE_POOL[i] = null;                    return state;                }            }        }        return new FindState();    }
//将FindState 里面的方法放入subscriberMethods list中,并将FindState 放回去继续使用    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {        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) {//如果引用变量为null将当前这个findState赋值过去,和上面的方法相对应                    FIND_STATE_POOL[i] = findState;                    break;                }            }        }        return subscriberMethods;    }
    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) { //判断方法是不是public                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())); //都满足将方法加入findState中                        }                    }                } 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");            }        }    }

通过apt的到方法

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {        FindState findState = prepareFindState();        findState.initForSubscriber(subscriberClass);        while (findState.clazz != null) {            findState.subscriberInfo = getSubscriberInfo(findState);//通过apt获取方法            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);    }
    private SubscriberInfo getSubscriberInfo(FindState findState) {        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();            if (findState.clazz == superclassInfo.getSubscriberClass()) {//先判断缓存中是否存在                return superclassInfo;            }        }        if (subscriberInfoIndexes != null) {//subscriberInfoIndexes 是通过apt处理器自动生成的文件            for (SubscriberInfoIndex index : subscriberInfoIndexes) {                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);                if (info != null) {                    return info;                }            }        }        return null;    }

订阅

    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);//获取subscriptionsByEventType map对象,用于post的时候通过eventtype获取订阅者的信息        } 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);//获取typesBySubscriber map对象,unregister时会用到        }        subscribedEvents.add(eventType);        if (subscriberMethod.sticky) {//如果是sticky事件,马上post            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);            }        }    }

发布事件

//通过threadMode来确认使用哪个线程执行订阅者的订阅函数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 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);        }    }

其中mainThreadPoster继承自Handler、backgroundPoster和asyncPoster都继承自Runnable

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 coolpad手机解锁图案忘了怎么办 装死兔严重掉毛怎么办 兔子嘴巴磕破了怎么办 嘴巴里面摔烂了怎么办 兔子的鼻子损了怎么办 两个人嘴巴被粘牙糖粘住怎么办 小鸟被老鼠粘粘住了怎么办 小猫被老鼠粘粘住怎么办 羊子嘴巴烂了怎么办 小孩突然嘴肿了怎么办 电视机图像颜色变了 怎么办 冰沙床垫结块了怎么办 冰沙床垫融化了怎么办 脚真菌感染肿了怎么办 水雾魔珠被吃了怎么办 怀孕40天出血了怎么办 联璧金融里的钱怎么办 提现的钱不对怎么办 究极日月蛋太多怎么办 人脸识别不匹配怎么办 地下城没有属强怎么办 传奇属性点错了怎么办 龙之谷技能太多怎么办 龙之谷pk卡怎么办 为什么访问别人空间没有记录怎么办 被蚊孑咬了有小红包怎么办 微信建了个打牌群找不客源怎么办 三星手机一直停在开机画面怎么办 微信猜拳被骗了怎么办 组队领金币的码怎么办 cad画图时鼠标飘怎么办 玩迷你世界很卡怎么办 玩迷你世界太卡怎么办 迷你世界太卡了怎么办 把线稿画在背景里了怎么办 蜗牛在家里跑了怎么办 小孩总是跟大人犟嘴怎么办 鹅当宠物养拉屎怎么办 金毛肚子胀很大怎么办 被小白兔咬了怎么办 仓鼠养在家里有味怎么办