EventBus源码解析,逐步源码流程

说明

EventBus是Android常用的三方框架之一。通过发送通知,在其他页面去做一些同步的事情,方便快捷。类似于观察者(但并不是),当观察到某个数据变化,就会立刻做改变,但是和内部和观察者其实不一样,它的思想是AOP切面编程思想。内部代码不多,大概30个类。

源码分析

1) getDefault()

 /** 
 Convenience singleton for apps using a process-wide EventBus instance. 
 */
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

EventBus的所有方法调用都需要通过EventBus.getDefault()调用,getDefault()其实就是获取的一个全局单例defaultInstance。这里同一个默认构造函数初始化了EventBus。

它的源码:

/**
 * Creates a new EventBus instance; each instance is 
 * a separate scope in which events are delivered. To use a
 * central bus, consider {@link #getDefault()}.
 */
public EventBus() {
    this(DEFAULT_BUILDER);
}

其内部调用了一个有参的构造函数,传入了一个default_builder,这个default_builder就是EventBusBuilder。

有参的EventBus

EventBus(EventBusBuilder builder) {
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>();
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    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;
    executorService = builder.executorService;
}

EventBus最终的初始化是在这里,这里做了很多处理。依次分析下构造函数中属性的含义。

1.1) subscriptionsByEventType

首先是subscriptionsByEventType,它的类型是Map<Class<?>, CopyOnWriteArrayList>,这里可以看出来,这个subscriptionsByEventType存放的是当前订阅者里面的所有注册方法。
Subscription这个类就是方法的实现,看一下里面代码:

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    /**
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, 
     * which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}

可以看到这个类中的代码其实很少,里面就是存放了就是一个Object类型的subscriber(注册的时候传进来的订阅者类),一个SubscriberMethod,里面存放的是这个subscriber中注册方法的数据。
SubscriberMethod

/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }

    private synchronized void checkMethodString() {
        if (methodString == null) {
            // Method.toString has more overhead, just take relevant parts of the method
            StringBuilder builder = new StringBuilder(64);
            builder.append(method.getDeclaringClass().getName());
            builder.append('#').append(method.getName());
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}

SubscriberMethod内部存放的就是方法的数据,其中method就是需要执行的方法。通过反射获取到的。
threadMode是线程类型,包括

  1. POSTING:事件发送者在哪个线程,那么就在哪个线程回调@Subscribe所注解的方法,同时这是默认也是官方推荐的模式
  2. MAIN:无论事件发送者在那种线程,都在ui线程中回调,如果发送者不再主线程,那就通过handler切换线程
  3. MAIN_ORDERED:在ui线程中回调,但是它永远都通过handlerpost来切换线程,通过消息队列来进行,无论发送者在哪个线程,所以肯定能够避免ui线程阻塞
  4. BACKGROUND:在子线程中回调被注解的方法,同样如果事件发送者就在子线程,那么直接回调了,如果不在的话,就会利用BackgroundPoster来切换线程
  5. BackgroundPoster是线程Runnable
    ASYNC:代表回调的线程跟事件发送的线程总是不在一个线程
    eventType事件类型,因为EventBus是通过参数类class去区分执行方法的,所以这个eventType的类型就是Class<?>
    priority分发优先级
    sticky是否粘性分发,在粘性分发的情况下,注册者比发送者更晚注册也可以收到。

1.2) typesBySubscriber

类型Map<Object, List<Class<?>>>,key是订阅者,value是当前订阅者中订阅的类型

1.3) stickyEvents

类型Map<Class<?>, Object>,粘性事件

1.4) mainThreadPoster

类型HanderPoster,继承实现了Handler,在ThreadMode切换到主线程执行的时候,通过Handler进行线程通讯,内部handlerMessage实现了一个死循环,通过不断获取自定义的PendingPostQueue消息队列,以及消息体PendingPost,处理消息。调用handler的时候是通过HanderPoster内部的enqueue方法调用,内部是对PendingPostQueue队列的操作。

final class HandlerPoster extends Handler {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

1.5) backgroundPoster

后台执行方法处理。类型BackgroundPoster,其内部是一个Runnbale,在ThreadMode是BACKGROUND的时候会调用,它也是通过PendingPostQueue队列来管理数据,在run方法中实现了死循环,通过enqueue方法调用添加消息。
主要注意的是在enqueue方法中,PendingPostrQueue执行的时候是添加了同步锁的,所以说明该方法一次只会执行一条数据处理。

final class BackgroundPoster implements Runnable {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

1.6) asyncPoster

后台执行方法处理。类型AsyncPoster,其内部也是一个Runnbale,在ThreadMode是ASYNC的时候会调用。它会每次启动一个新线程,且enqueue是直接执行,没有同步锁,所以可能会并发,并且将该poster存放到线程池。run方法也会直接执行处理。

class AsyncPoster implements Runnable {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        eventBus.getExecutorService().execute(this);
    }

    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}

1.7) EventBusBuilder

配置部分EventBus的设置,将一些配置同意存放到了EventBusBuilder中。

2) register()

事件注册,EventBus必须在需要在响应的类中注册和取消注册,register就是注册方法。

/**
 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
 * are no longer interested in receiving events.
 * <p/>
 * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
 * The {@link Subscribe} annotation also allows configuration like {@link
 * ThreadMode} and priority.
 */
public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

首先方法中传递的subscriber是我们的注册者,也就是我们常使用的activity或者fragment(但是不是一定只有这两个),首先通过getClass方法获取到当前Object的类型。然后通过subscriberMethodFinder.findSubscriberMethods获取到当前类中所以已经注册的方法,然后遍历这个list,将其添加到方法集合map中。

2.1) subscriberMethodFinder.findSubscriberMethods

首先subscriberMethodFinder是在EventBus的构造方法中初始化的。

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

方法首先通过METHOD_CACHE获取方法列表,其中METHOD_CACHE是当前所有已经注册了的方法的集合缓存。如果这个集合中存在相同可以的数据,也就是list不为空的时候,就直接返回这个数据。
如果过去不到,缓存中没有数据,那就通过反射获取到当前类中所有的方法,然后判断方法中是否存在注解,如果存在就返回方法(findUsingReflectionInSingleClass())。

2.2) subscriber()

最终执行订阅方法的方法。内部主要逻辑,就是将类和方法绑定到subscriptionsByEventType和typesBySubscriber中,在这里subscriber()在方法的最后处理了粘性event的list,通过遍历stickyEvents,并且处理当前订阅者是否需要接受粘性事件。

3) unregister()

取消订阅,和register成对出现,通常在页面销毁时调用,主要处理就是在subscriptionsByEventType和typesBySubscriber中移除对应数据

/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

4) post()

发送消息,对应接收者将会处理消息。

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

首先获取当前线程,然后获取到当前线程的消息队列Queue,然后将当前post的消息添加到队列中。然后判断当前线程是否在post消息,如果没有就执行下面代码,首先判断是否在主线程执行,然后通过postSingleEvent()发送队列中的第一条消息,并将该消息从队列中移除。

4.1) postSingleEvent()

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) {
            Log.d(TAG, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

在方法中, lookupAllEventTypes(eventClass)是在事件类型缓存中查找是否存在相同的事件类型,如果存在就直接返回,如果不存在就创建。然后通过postSingleEventForEventType()调用postToSubscription(subscription, event, postingState.isMainThread)方法,最终在postToSubscription方法中去执行处理。

4.2) postToSubscription()

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

在postToSubscription中,通过ThreadMode类型,判断是否直接去执行调用方法还是通过handler或者backgroundPoster等去执行。最终都会调用invokeSubscriber()方法处理

4.3) invokeSubscriber()

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

最终都是调用Method.invoke去执行该方法。

5) postSticky()

粘性事件发送,通过postSticky发送,当发送粘性事件后,在事件不移除的情况下,先发送,后注册的订阅者也可以收到消息。

/**
 * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
 * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
 */
public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // Should be posted after it is putted, in case the subscriber wants to remove immediately
    post(event);
}

通过源码其实看出来,它内部也是同post调用,不同的是其传递的event添加到了stickyEvents中了。然后在stickyEvents中,post后会处理已经订阅了的事件,然后在新订阅的页面,在register的时候,调用subscriber()方法(章节2.2)后去判断是否需要执行该stickyEvents里面的方法。

Sunanang

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值