EventBus简单使用以及源码分析

EventBus相关文章虽然对,作为学习笔记使用,有问题希望能够尽情提出,共同交流
蒋八九

基本使用:

添加依赖:

implementation 'org.greenrobot:eventbus:3.1.1'

EventBus的注册:

EventBus.getDefault().register(this);

事件的发送:

普通事件的发送:

EventBus.getDefault().post(new MessageEvent("第二页点击后关闭"));

粘性事件的发送:

EventBus.getDefault().postSticky(new MessageEvent("发送Sticky事件"));

事件的接收:

普通事件的接收

@Subscribe(threadMode = ThreadMode.MAIN)                         主线程接受:
@Subscribe(threadMode = ThreadMode.BACKGROUND)                   子线程接受:
@Subscribe(threadMode = ThreadMode.POSTING)                      不切换线程接受:
@Subscribe(threadMode = ThreadMode.ASYNC)                        异步线程接受:
public void EventMAIN(MessageEvent messageEvent) {
    Log.e(TAG, "EventBus:EventMAIN:" + Thread.currentThread());
}

粘性事件的接收:

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void XXX(MessageEvent messageEvent) {
    Log.e(TAG, "EventBus:sticky:接受Sticky事件" + messageEvent.getMessage());
}

源码分析:

设计模式:单例,订阅者模式

事件注册:

首先getDefault(),然后register()注册

EventBus.getDefault().register(this);

//这里getDefault主要为了获取构造,初始化三个hashmap,和三个poster
    EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        //存储被订阅类型(如EventMessage)和订阅者集合(如Subscription对象是个CopyOnWriteArrayList,其中封装了MainActivity和订阅方法subscriberMethod)
        subscriptionsByEventType = new HashMap<>();
        //存储订阅者(如MainActivity)和被订阅者类型集合(如EventMessage,是个ArrayList)
        typesBySubscriber = new HashMap<>();
        //粘性事件的集合
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        //主线程poster,继承handler,用来切换到主线程
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        //子线程poster,生成的runnable任务最终通过excecute提交给cacheThreadpool线程池来执行任务
        backgroundPoster = new BackgroundPoster(this);
        //异步poster,生成的runnable任务最终通过excecute提交给cacheThreadpool线程池来执行任务
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        //这个类用来查找所有被@Subscribe注释的方法的信息
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        //jdk1.5中的cacheThreadPool线程池
        executorService = builder.executorService;
    }

register过程:
1、methodfinder对象,使用反射从class中找出所有的方法
2、遍历所有方法,找出满足(被public修饰&&且只有一个入参&&且被@Subscribe注释)的方法集合
3、遍历集合,并添加到三个容器中,即完成注册。

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}
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);
    }
这里当一个类添加了regist方法,但是找不到满足条件的方法,那么就抛出异常。
    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;
    }
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    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);
}
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
首先获取所有的方法。
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    for (Method method : methods) {
条件一、方法Modifiers修饰语必须是public
        int modifiers = method.getModifiers();
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();
条件二、方法入参个数必须只有一个,否则抛异常提示
            if (parameterTypes.length == 1) {
条件三、方法必须有Subscribe注解
                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");
        }
    }
}
当前类找完去父类再继续找一遍,直到找完为止,这里应该把AndroidX也适配上了
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;
        }
    }
}
得到所有的subcribeMethods之后,遍历并对subscriptionByEventType、typesBySubscriber进行装箱。
subscriptionByEventType:订阅类型为key,Subscription(class,subscriberMethod)为value;value按优先级大小添加
typesBySubscriber:class为key,subcribeMethods集合为value;
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(
    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            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);
        }
    }
}

事件发送

发送普通事件:

1、将消息添加到数组中,就是个arraylist数组。
2、如果支持继承,则将消息事件的父类和接口类都找出来

EventBus.getDefault().post("haha");
public void post(Object event) {
首先拿到postingState对象,然后将event事件添加到ArrayList中去,然后遍历数组进行发送。
    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;
        }
    }
}
1、支持继承:找出所有事件的父类和接口,依次遍历发送;不支持继承,直接发送
2、从subcriberByEventType中根据事件获取methodsInfo信息去遍历发送。
3、发送不成功表示发送事件没有被订阅,则抛出异常提示语,并将消息发送至NoSubcribeEvent中。
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) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}
从subscriptionsByEventType中获取发送事件对应的所有subscriptions订阅信息,去遍历发送。
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完成发送。
1、判断线程类型:POSTING?MAIN?BACKGROUND?ASYNC?
2、如果满足发送条件直接调用invokeSubscriber发送事件。
3、如果需要切换线程,则添加到对应的poster中。
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 {
                invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND:
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
            asyncPoster.enqueue(subscription, event);
            break;
    }
}
不论主线程还是子线程还是异步,都将事件封装到PendingPost对象中,添加到PendingPostQueue双向队列中,先进先出取值。
mainThreadPoster:继承了handler,通过handler机制发送消息。
backgroundPoster、asyncPoster:继承了runnable,通过线程池提交处理消息。
public void enqueue(Subscription subscription, Object event) {
    PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
    synchronized (this) {
        queue.enqueue(pendingPost);
        main消息:
	sendMessage(obtainMessage()
	子线程和异步消息:
	eventBus.getExecutorService().execute(this);
    }
}
最终都是通过反射方法调用invoke发送消息。
void invokeSubscriber(Subscription subscription, Object event) {
        subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
}

粘性事件发送

1、先将事件存放到stickyEvents的map集合中去
2、然后将他当做普通事件发送给当前Activity中的同名事件,当前事件不需要sticky==true。

EventBus.getDefault().postSticky("haha");
首先将事件存放到stickyEvents的map集合中去
public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    post(event);
}
当打开另一个类走到subscribe的时候,遍历方法是否是sticky事件,如果是的话,从stickyEvents中获取缓存的粘性事件,调用postSubscribe——>invokeSubscribe将时间发送出去。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    。。。。。。。

    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            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);
        }
    }
}

优缺点:

优点:3.0使用的编译的时注解,这个类似与ARouter,2.0使用的运行时注解,这个依赖与java的反射规则。

猜你喜欢

转载自blog.csdn.net/massonJ/article/details/107878362