EventBus代码解读

前言、提问
1.EventBus如何使用?
2.EventBus的执行流程?
3.onEvent****(Object o)与onEvent****(具体的类型)比较,哪个效率更高?各有什么好处?
4.EventBus注册查找等是在UI线程实现吗?EventBus的消息处理如何实现在UI线程、后台线程、异步线程里运行?
5.post()和postStick()方法的区别?
6.EventBus中使用到哪些设计模式?
7.不调用EventBus.unregister()为何会造成内存泄露?
8.onEvent系列方法在异步线程中执行是同一个线程还是多个线程?
9.EventBus中优先级的用处?
10.EventBus中用到的技术点

一、EventBus使用方法和执行流程
1.1 使用方法
      EventBus的使用包括收发消息。发送消息通过调用EventBus.getDefault().post()或postStick()方法。接收消息,需要在Subscriber(如Activity、Fragment)中的onCreate()中调用EventBus.getDefault().register(),在onDestroy()调用EvenBus.getDefault().unregister()方法,在onEvent系列方法中对消息进行处理,可以区分在UI线程或者非UI线程中处理。

1.2 执行流程
       EventBus.getDefault()首先通过单例模式创建或获取全局唯一的对象。
       当调用register()时,会在参数类的文件内寻找onEvent系列方法。如果找不到就抛出异常;如果找到就将参数类和onEvent***方法、消息的类型(class)等信息以键值对的形式存储在EventBus对象里的HashMap中。当调用unregister()时,会将参数类对应的值删除。如果只调用register(),未在onDestroy()中调用unregister(),会造成内存泄露。
       当调用post***()方法时,会根据发送的消息类型,找到能处理该类型消息的所有类对象和消息处理方法,并根据是否在UI线程进行执行。如果在UI线程,则通过Handler执行;如果在异步线程,则在EventBus中创建的线程池中执行。

二、代码导读
       阅读代码前,先记住几个类或名词。
       注册EventBus的类称为Subscriber(register()和unregister()传入的参数,实际处理消息的类)
       封装消息的类是PendingPost
       消息的类型称为EventType,是消息类的class(类字面常量,onEvent***()方法传入的形参是消息类的对象)
       封装消息处理方法的类是SubscriberMethod
       封装Subscriber、消息处理方法和优先级信息的类是Subscribtion
       
2.1  getDefault() 
       使用EventBus,首先要用到EventBus的getDefault()方法。
       getDefault()采用单例模式。首先判断defaultInstance是否为空,如果不为空则直接返回;如果为空,加同步锁,保证在不同线程里同时调用返回的是同一个对象。在同步块中,仍然判断是否为空,防止在其他线程中已经创建了EventBus对象;如果为空,则创建,并返回。
/** 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;
}
      其中,defaultInstance变量是volatile修饰的EventBus对象句柄,保证在任一线程中发生更改,在其他线程中其值都是最新的。
static volatile EventBus defaultInstance;

2.2 EventBus的构造函数
       getDefault()创建EventBus的对象,会调用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);
}
这里要注意,使用单例模式来设计的类,其构造函数应该为private。但这里声明为public,破坏了单例的设计。(为何要这样?)
EventBus的构造函数使用了Builder模式。DEFAULT_BUILDER是EventBus内部声明的static变量。
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
上面EventBus的公有构造函数调用了它的重载方法。
EventBus(EventBusBuilder builder) {
   subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();
   typesBySubscriber = new HashMap<Object, List<Class<?>>>();
   stickyEvents = new ConcurrentHashMap<Class<?>, Object>();
   mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
   backgroundPoster = new BackgroundPoster(this);
   asyncPoster = new AsyncPoster(this);
   subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);
   logSubscriberExceptions = builder.logSubscriberExceptions;
   logNoSubscriberMessages = builder.logNoSubscriberMessages;
   sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
   sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
   throwSubscriberException = builder.throwSubscriberException;
   eventInheritance = builder.eventInheritance;
   executorService = builder.executorService;
}

2.2.1 subscriptionsByEventType
        subscriptionsByEventType是存储消息类型(EventType)和消息处理方法(onEvent***())等信息的数据结构。
        如Activity的activitya对象和activityb对象都有onEvent***(A a)方法,则subscriptionsByEventType存储A.class(key)和[由activitya、onEvent***、priority等字段拼装的Subscribtion, 由activityb、onEvent***、priority等字段拼装Subscribtion](value)。
2.2.2 typesBySubscriber
       typesBySubscriber是存储消息处理对象(Subscriber)和消息类型列表(EventType)的数据结构。如Activity的activitya对象有onEvent**(A a)和onEvent***(B b)两个方法,则typesBySubscriber中会存储activitya(key)和[A.class, B.class](value)。
typesBySubscriber的添加在register()中:
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
    subscribedEvents = new ArrayList<Class<?>>();
    typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
删除在unregister()中:
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
typesBySubscriber.remove(subscriber);
因此如果在activitya对象的onDestroy中未调用unregister()方法,由于typesBySubsciber变量中仍包含activitya的对象句柄,会造成activitya无法被垃圾回收,从而造成内存泄露。
2.2.3  mainThreadPoster
      mainThreadPoster的类型是HandlerPoster,继承于Handler,内有PendingPostQueue对象。其中,PendingPostQueue是一个自定义队列(先进先出),有enqueue()和poll()方法。
      HandlerPoster有enqueue()和重写于Handler的handleMessage()方法。其中,enqueue()方法将消息(PendingPost)添加到PendingPostQueue对象中,并通过Handler的sendMessage()方法,调用自身的handleMessage()方法。
      在handleMessage中,通过queue.poll()方法消息(PendingPost)取出,进行处理,处理完成后,如果处理时间超过单次最大处理时间,则通过sendMessage加入到UI线程的消息队列中,结束本次handleMessage()的调用。如果未超过单次最大处理时间,则继续通过poll()方法获取下个消息(PendingPost),继续处理,直到消息都处理完或者总处理时间超过单次最大处理时间。这种实现方式,既保证了UI线程不会被长时间占用,又加快了消息的处理速度(从发出到处理完的时间尽量短)。
2.2.3.1 HanlerPoster的实现依赖Looper线程,不一定是UI线程,
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
    super(looper);
    this.eventBus = eventBus;
    this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
    queue = new PendingPostQueue();
}
看下mainThreadPoster 的创建:
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
传入的是Looper.getMainLooper(),因此消息的处理是在UI线程中完成的。
2.2.3.2 看下HandlerPoster的enqueue()方法:
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");
            }
        }
    }
}
其中PendingPost内部使用了对象池,避免对象反复创建销毁,有兴趣的可以看下源码。
2.2.3.3 这里有个疑问,PendingPost和Message的实现基本一致,都是使用对象池,而且PendingPostQueue和MessageQueue的实现也一致,那么为何不直接使用Message和MessageQueue?
看下HandlerPoster的handlerMessage()方法
@Override
public void handleMessage(Message msg) {
    boolean rescheduled = false;
    try {
        long started = SystemClock.uptimeMillis(); //Returns milliseconds since boot, not counting time spent in deep sleep.
        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;
    }
}
区别在于如果直接使用Message,单次handleMessage(),只执行一个subscription。
而使用PendingPost,单次handlerMessage(),可以执行0个(如果为空)或一个或多个subscription;而且,当handlerActive的情况下,enqueue()操作不需要调用sendMessage()。
此处应注意// Check again, this time in synchronized,具体见2.2.4分析。

2.2.4 BackgroundPoster
       BackgroundPoster实现了Runnable接口,由EventBus的内置线程池(见2.2.7)运行。与HandlerPoster相同,enque()方法将PendingPost对象添加进队列,不同的是BackgroundPoster是通过ExecutorService进行执行。
       在BackgroundPoster的run方法中,从队列中取出pendingPost并执行,实现了在非UI线程中执行的意图;同时,通过无限循环,会一直执行到队列中没有数据且wait(1000)后再取也没有,才会退出线程。这种实现方式与IntentService的实现思路一致。当有BackgroundThread执行时,会将工作交给正在执行的BackgroundThread,而不是再创建新的BackgroundThread,避免了线程的重复创建与销毁;同时,如果一直没有新的消息需要处理,为了避免线程一直在后台执行,浪费CPU和电量,会将线程停止。
@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;
    }
}
这里需要注意的是,继承Thread的线程多次start()会运行错误,而implement Runnable 的线程多次start()却不会运行出错。
比较new Thread().start();与
Runnable r  = new Runnable();
new Thread(r).start();
new Thread(r).start();可以看到后者并不违背Thread.start()后不能再次start()的原则。
但是不能理解的是为何需要checkAgain需要in synchronized?这里需要看下enqueue()方法
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);
        }
    }
}
       所以synchronized(this)针对的是executorRunning变量,由于enqueue()方法是在调用enqueue()方法的线程里执行,而run()方法在工作线程中执行,所以对executorRunning变量更改需要做同步处理。至于将queue.enqueue()和queue.poll()方法也放进去,是因为如果将其放在外面,那么有可能出现先执行queue.poll(),为null;再执行queue.enqueue(pendingPost);之后执行executorRunning为false,线程停止,那么这个pendingPost就未被处理导致遗漏。
      从以上对BackgroundPoster代码的分析可以看出,onEventBackground()的处理,不一定是在不同的线程中,也不一定在相同的线程中。

2.2.5 AsyncPoster
        AsyncPoster与BackgroundPoster同样实现了Runnable,但AsyncPoster中一个线程的创建与销毁只伴随一个消息的处理,保证每个消息的处理(onEventAsync())都是在不同的线程中执行。

2.2.6 ExecutorService
        executorService赋值为builder的executorService 而EventBusBuilder中,
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
是全局唯一的线程池。

2.2.7 SubscriberMethodFinder
        subscriberMethodFinder是在注册EventBus的Subscriber(如Activity、Fragment)中查找消息处理方法(SubscriberMethod)的类,将查找到的方法存储在其内部的methodCache中。
private static final Map<String, List<SubscriberMethod>> methodCache = new HashMap<String, List<SubscriberMethod>>();
其查找方法的函数为findSuscriberMethods()
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    String key = subscriberClass.getName();
    List<SubscriberMethod> subscriberMethods;
    synchronized (methodCache) { 
        subscriberMethods = methodCache.get(key); //先从缓存中读取
    }
    if (subscriberMethods != null) {
        return subscriberMethods; // 缓存中有,直接返回
    }
    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) {
            String methodName = method.getName();
            if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { //private static final String ON_EVENT_METHOD_NAME = "onEvent";
                 int modifiers = method.getModifiers(); //获取参数修饰
                 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //公有方法且非忽略方法
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length == 1) { //只处理一种类型
                        String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
                        ThreadMode threadMode;
                        if (modifierString.length() == 0) { // 默认为当前线程中执行
                            threadMode = ThreadMode.PostThread;
                        } else if (modifierString.equals("MainThread")) {//主线程中执行
                            threadMode = ThreadMode.MainThread;
                        } else if (modifierString.equals("BackgroundThread")) {//后台线程中执行
                            threadMode = ThreadMode.BackgroundThread;
                        } else if (modifierString.equals("Async")) {//完全异步线程中执行
                            threadMode = ThreadMode.Async;
                        } else { // 其他种不处理
                            if (skipMethodVerificationForClasses.containsKey(clazz)) { 
                                continue;
                            } else {
                                throw new EventBusException("Illegal onEvent method, check for typos: " + method);
                            }
                        }
                        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
                            subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                        }
                    }
                } else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
                    Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
+ methodName);
                }
            }
        }
        clazz = clazz.getSuperclass();
    }
    if (subscriberMethods.isEmpty()) {
         throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME);
    } else {
         synchronized (methodCache) {
              methodCache.put(key, subscriberMethods);
        }
        return subscriberMethods;
    }
}
       如果为onEventMainThread(EventA a),则methodKey为onEventMainThread>*.*.EventA,threadMode为ThreadMode.MainThread,eventType为*.*.EventA(EventA的包名+类名)。

2.2.8 stickyEvents 
        stickyEvents存储消息的类型信息(class)和消息的对象,如postSticky(EventA  eventa),stickyEvents中会增加EventA.class(key)和eventa(value)的键值对。

2.2.9 eventInheritance
        eventInheritance表明是否开启消息查找父类模式,默认为true。举个例子,存在EventA和EventB,其中EventB继承于EventA,如果Activity activitya中有onEvent***(EventA eventa)方法。当调用post(EventB eventb)时,如果eventInheritance为true,那么activitya的onEvent***(eventA eventa)方法也会被执行;如果eventInheritance为false,则不会。

2.2.10 eventTypesCache
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();
eventTypesCache是存储消息类型字面量和消息及其父类的类型字面量列表的Map。拿String类来说,eventTypesCache存储以String.class(key)和[String.class, Object.class]为键值对的数据。
/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
    synchronized (eventTypesCache) {
        List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
        if (eventTypes == null) {
            eventTypes = new ArrayList<Class<?>>();
            Class<?> clazz = eventClass;
            while (clazz != null) {
                eventTypes.add(clazz);
                addInterfaces(eventTypes, clazz.getInterfaces());
                clazz = clazz.getSuperclass();
            }
            eventTypesCache.put(eventClass, eventTypes);
        }
        return eventTypes;
    }
}

2.3 register()和unregister()方法
2.3.1 register()方法
EventBus的register()方法调用了自己的重载方法,
public void register(Object subscriber) {
    register(subscriber, false, 0);
}
regsiter(subscriber, sticky, priority)
private synchronized void register(Object subscriber, boolean sticky, int priority) {
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
        subscribe(subscriber, subscriberMethod, sticky, priority);
    }
}

2.3.1.1 findSubscriberMethods()
       首先通过subscriberMethodFinder通过类型信息获取subscriber类中定义的onEvent***()方法列表,存储在subscriverMethods中。具体见2.2.7。
2.3.1.2 subscribe()
       之后,调用subscribe方法
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
    Class<?> eventType = subscriberMethod.eventType;
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);//获取注册了消息类型(eventType)的注册者
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
    if (subscriptions == null) {//如果没注册该消息类型
        subscriptions = new CopyOnWriteArrayList<Subscription>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {// 如果已经注册,此种情况为,针对同一个Subscriber对象(如Activity activity、Fragment fragment等)中调用了两次register()方法,无论是否是重载的register()方法
        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);
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {// 按优先级插入,优先级高的在前面,优先级低的在后面
        if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//按消息类型添加subscriber
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<Class<?>>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);

    if (sticky) { //??? what meaning
        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);
        }
    }
}

2.3.1.2.1 CopyOnWriteArrayList的add(int, E)方法
public synchronized void add(int index, E e) {
    Object[] newElements = new Object[elements.length + 1];
    System.arraycopy(elements, 0, newElements, 0, index);
    newElements[index] = e;
    System.arraycopy(elements, index, newElements, index + 1, elements.length - index);
    elements = newElements;
}
add(E)方法
public synchronized boolean add(E e) {
    Object[] newElements = new Object[elements.length + 1];
    System.arraycopy(elements, 0, newElements, 0, elements.length);
    newElements[elements.length] = e;
    elements = newElements;
    return true;
}
可以看到CopyOnWriteArrayList与ArrayList的区别,ArrayList是声明一个定长数组,添加数据直接在数组里添加,当数目超过数组长度时,再声明一个更长的数组,将数据从旧数组copy到新数组里。而CopyOnWriteArrayList是ArrayList的特例,它的数组总是被填满的,每次添加数据时,都伴随着新数组的创建,而且新数组长度比旧数组长度只多一,因此每次添加操作都伴随着数据的复制。
2.3.1.2.2 sticky 参数
????
2.3.1.2.3 看下subscriptions.contains(newSubscription),其取决于ArrayList中的object是否equals给定的参数。Subscription类中重写了equals()方法。
@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;
    }
}
因此如果针对相同的subscriber对象调用register()两次,无论是否为重载的,都会走到
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);

2.3.2 unregister()方法
unregister()方法必须要调用,否则会造成内存泄露,具体原因见之前对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) {
            unubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
     整体思路就是把不需要再接收消息的Subscriber对象和处理方法(subscription)从HashMap中清除掉。比较有意思的是unubscribeByEventType()里for循环的写法。
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unubscribeByEventType(Object subscriber, Class<?> eventType) {
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) {
            Subscription subscription = subscriptions.get(i);
            if (subscription.subscriber == subscriber) {
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}
       首先,一个subsciptions列表中可以有多个subscription的subscriber与传入的subscriber相同,这是由于对相同的事件类型,可以有不同的threadMode,即一个Subscriber中,可以有onEventMainThread(EventA eventa),也可以有onEventBackgroundThread(EventA eventa)、onEventAsync(EventA eventa)、onEvent(EventA eventa)。
       其次,在对List做遍历操作的同时更改List的内容,如果书写不当,是会抛出Concurrent异常的。此处的写法无问题,很值得借鉴。

2.4 post()与postSticky()
/** Posts the given event to the event bus. */
public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get(); //获取当前线程中postMessage的状态
    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;
        }
    }
}

2.4.1  currentPostingThreadState是EventBus对象内部的ThreadLocal类型的变量,虽然是一个对象,但在不同的线程中调用get()方法,会返回该线程的PostingThreadState变量,每个线程的PostingThreadState都指向不同的对象句柄。
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    @Override
    protected PostingThreadState initialValue() {
         return new PostingThreadState();
    }
};

2.4.1.1 这里用到了java的匿名内部类,实际上是创建一个继承于ThreadLocal类的对象,完整写法为:
class ThreadLocalSub<T> extends ThreadLocal {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
}
private final ThreadLocalSub<PostingThreadState> currentPostingThreadState = new ThreadLocalSub<PostingThreadState>();

2.4.1.2 看下ThreadLocal的get()方法
/**
 * Returns the value of this variable for the current thread. If an entry
 * doesn't yet exist for this variable on this thread, this method will
 * create an entry, populating the value with the result of
 * {@link #initialValue()}.
 *
 * @return the current value of the variable for the calling thread.
 */
@SuppressWarnings("unchecked")
public T get() {
    // Optimized for the fast path.
    Thread currentThread = Thread.currentThread();
    Values values = values(currentThread);
    if (values != null) {
        Object[] table = values.table;
        int index = hash & values.mask;
        if (this.reference == table[index]) {
            return (T) table[index + 1];
        }
    } else {
        values = initializeValues(currentThread);
    }

    return (T) values.getAfterMiss(this);
}
       其中,Thread对象内部存有Values对象, 如果Values为空,则创建一个,并赋值给Thread的Values对象;如果不为空,则在values.table中寻找当前ThreadLocal对象的值(Thread可以有多个ThreadLocal变量),如果找到,则直接返回;如果未找到,则创建,实际上调用的是ThreadLocal的initialValue方法(具体可见values.getAfterMiss(this)方法)。另外这是一种很好的解耦方式。

2.4.1.3 PostingThreadState类存储有当前线程中EventBus发送消息的相关信息,如事件队列、当前是否主线程、当前发送的消息、消息类型、是否被取消、是否在发送。
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
    final List<Object> eventQueue = new ArrayList<Object>();
    boolean isPosting;
    boolean isMainThread;
    Subscription subscription;
    Object event;
    boolean canceled;
}
      这里需要提个问题:为什么需要使用ThreadLocal变量,而不是一个全局的PostingThreadState对象?
      答案是明显的,如果使用一个全局的PostingThreadState变量,那么多个线程中调用post()方法就必须进行同步操作,反复获取锁、丢弃锁,造成性能消耗;同时,post操作沦为一个顺序的操作,虽然可以多线程中调用,却只能一个接一个的发送。而使用ThreadLocal变量,每个线程中自己进行状态维护,可以并行执行,且不需要同步,性能消耗小。
      但另一个问题来了,由于使用了ThreadLocal变量,所以post()代码只需要考虑单个线程执行的情况,那么使用isPosting变量进行锁限制,就很多余了。因为一个线程里,必然要执行完前一个方法,才执行下个方法。这是为什么呢?

2.4.2 post()方法主要调用了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));
        }
    }
}
postSingleEvent()方法又主要调用了postSingleEventForEventType()方法。
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;
}
这里有个问题,如果subscriptions是ArrayList类型,对subscriptions的遍历不在synchronized语句块里,多线程情况下,应该有一定的概率会出现问题。
但是需要注意的是:subscriptions是CopyOnWriteArrayList类型的,它在java.util.cocurrent包中,在一个线程中对其遍历,在另外线程中,对其进行更改,是经过同步处理的。
最终调用的是postToSubsciption方法,结合之前说的mainThreadPoster、backgroundPoster、asyncPoster,很好理解。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case PostThread:
            invokeSubscriber(subscription, event);
        break;
        case MainThread:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
        break;
        case BackgroundThread:
            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);
    }
}
主要看下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);
    }
}

三、 onEvent****(Object o)与onEvent****(具体的类型)比较,哪个效率更高?各有什么好处?
onEvent***(Object o)这种写法,在subscriptionsByEventType里,以Object.class(key)和subscribers(value)为键值对存储。
在eventInheritance为true时,post()任意EventType的消息,都会调用onEvent***(Object o)方法。而eventInheritance为false时,只有post(Object o)时,才会调用onEvent***(Object o)方法。与onEvent***(具体的类型)比较,自然是后者的效率高。EventBus的实现思路,其实就是通过类型信息来做事件区分的。

四、EventBus注册查找等是在UI线程实现吗?EventBus的消息处理如何实现在UI线程、后台线程、异步线程里运行?
EventBus注册查找等在调用的线程里实现,已经做了线程同步。
见2.2.3、2.2.4、2.2.5、2.2.6

五、post()和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. This can be registerSticky(Object) or getStickyEvent(Class).

六、设计模式
1.单例模式 见EventBus.getDefault()
2.Builder模式 EventBusBuilder
3.模版模式


七、不调用unregister()为何会造成内存泄露?
见2.2.2

八、onEvent系列方法中异步线程中是同一个线程还是多个线程?
见2.2.3、2.2.4、2.2.5、2.2.6

九、优先级的用处
先得到调用 见register()部分介绍

十、用得好的技术点
1.自定义消息队列
2.线程池和Runnable
3.对象池
4.设计模式
5.ThreadLocal
6.一些数据结构
7....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章