EventBus底层实现原理

2种思路去读EventBus源码

1.注册 EventBus.getDefault().register(this);

2.发送消息EventBus.getDefault().post();

根据1追到了findSubscriberMethodsWithReflection   根据反射查找订阅者,代码如下里面的内容不解释了,返回的是一个订阅方法的集合。

private List<SubscriberMethod> findSubscriberMethodsWithReflection(Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods = new ArrayList<SubscriberMethod>();
    Class<?> clazz = subscriberClass;
    HashSet<String> eventTypesFound = new HashSet<String>();
    StringBuilder methodKeyBuilder = new StringBuilder();
    while (clazz != null) {
        String name = clazz.getName();
        if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
            // Skip system classes, this just degrades performance
            break;
        }

        // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
        Method[] methods = clazz.getDeclaredMethods();
        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) {
                        String methodName = method.getName();
                        Class<?> eventType = parameterTypes[0];
                        methodKeyBuilder.setLength(0);
                        methodKeyBuilder.append(methodName);
                        methodKeyBuilder.append('>').append(eventType.getName());

                        String methodKey = methodKeyBuilder.toString();
                        if (eventTypesFound.add(methodKey)) {
                            // Only add if not already found in a sub class
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (strictMethodVerification) {
                    if (method.isAnnotationPresent(Subscribe.class)) {
                        String methodName = name + "." + method.getName();
                        throw new EventBusException("@Subscribe method " + methodName +
                                "must have exactly 1 parameter but has " + parameterTypes.length);
                    }
                }
            } else if (strictMethodVerification) {
                if (method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = name + "." + method.getName();
                    throw new EventBusException(methodName +
                            " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
                }

            }
        }

        clazz = clazz.getSuperclass();
    }
    return subscriberMethods;
}

 

然后看调用这个方法的地方

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection
    boolean forceReflection = subscriberClass.isAnonymousClass();
    List<SubscriberMethod> subscriberMethods =
            subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection);
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
        subscribe(subscriber, subscriberMethod);
    }
}

接下来咱们继续查看 subscribe(subscriber, subscriberMethod);,如下

划线部分核心代码,到此为止EventBus.getDefault().register(this);大概干了一这样一件事情

通过反射得到观察者(订阅者)的方法,事件和所在的线程

然后将这些参数组装后放入Map中,其中key为事件类型

 

// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<Subscription>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }

    // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
    // subscriberMethod.method.setAccessible(true);

    // Got to synchronize to avoid shifted positions when adding/removing concurrently
    synchronized (subscriptions) {
        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<Class<?>>();
        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);
        }
    }
}

 

-----------------------------------------------------------------------------------------------------------------------------

接下来看一下发送消息是怎么实现的

/** 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 = 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;
        }
    }
}

接着看画线部分方法,然后此方法中找到调用的postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)方法。划线部分是核心代码,头一个划线部分是从map中根据发送事件类型得到的一个类。这个类存储的是订阅的方法,所在的线程,不出意外的话下面应该用的是反射调用订阅的方法。拭目以待

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

 

接下来咱们看一下第二个划线部分的代码。里面基本全是反射

/**

*subscription   里面存储的是要调用方法的名字等信息

*event   此事件

*isMainThread  boolean 当前发送消息线程是不是UI主线程

*/

private void postToSubscription(Subscription subscription, Object event, boolean。isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {  //当时订阅方法所在的线程
        case PostThread:   //非主线程
            invokeSubscriber(subscription, event);
            break;
        case MainThread:  //ui主线程
            if (isMainThread) { //在主线程直接更新
                invokeSubscriber(subscription, event);
            } else { //通过handler发送消息,防止在自线程中更新UI的误操作
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BackgroundThread:
            if (isMainThread) { //主线程创建runable丢入线程池
                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);
    }
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值