EventBus 源碼分析

EventBus 源碼分析

分析源碼之前

EventBus 大神的 github烂叔,最好的老師皆看。

一、使用

我們?cè)谄綍r(shí)都會(huì)運(yùn)用 EventBus 去簡(jiǎn)化各個(gè)組件之間的通信痒给,相信使用了它之后感覺(jué)是真的方便了不少灰署,可以有效的對(duì)解耦發(fā)送方和接收方甥郑。

無(wú)論主線程中調(diào)用子線程的方法渗钉,還是子線程中調(diào)用主線程的方法郭厌,我們不必去寫(xiě)繁雜的 Handler ,也省去了內(nèi)存泄漏等的麻煩你踩。

首先我們簡(jiǎn)單的運(yùn)用一下 EventBus诅岩。

1、添加依賴(lài)

implementation 'org.greenrobot:eventbus:3.1.1'

2姓蜂、定義事件

public class Student {

    private String name;
    private String addr;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

3按厘、準(zhǔn)備訂閱者

聲明并注釋您的訂閱方法医吊,可選擇指定一個(gè)線程模型钱慢。

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void showSutednt(Student student) {
        Toast.makeText(this, student.toString(), Toast.LENGTH_SHORT).show();
    }

4、注冊(cè)和注銷(xiāo)訂閱者

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }

5卿堂、發(fā)布事件

Student student = new Student();
student.setAddr("北京");
student.setName("張三");
EventBus.getDefault().post(student);

二束莫、使用須知

1懒棉、基于「發(fā)布訂閱」

首先我們要明白它是基于「發(fā)布訂閱」模式,通過(guò) 發(fā)布者 「Publisher」 發(fā)布事件給 「EventBus」 览绿,EventBus 最后把事件分發(fā)給訂閱者 「Subscriber」 策严。<br />

<br />
image.png

2、四種線程模型

  • POSTING (默認(rèn)) :事件處理函數(shù)的線程和發(fā)布事件的線程在同一個(gè)線程饿敲。也就是直接操作妻导。
  • MAIN :事件處理函數(shù)的線程是主線程。注意不能有耗時(shí)操作怀各。
  • BACKGROUND:事件處理函數(shù)在后臺(tái)線程(只有一個(gè)后臺(tái)線程)倔韭。
  • ASYNC:無(wú)論事件發(fā)布的函數(shù)在哪里,始終會(huì)新建一個(gè)新線程來(lái)運(yùn)行瓢对。

分析源碼

一寿酌、EventBus 的創(chuàng)建

EventBus#getDefault()

    public static EventBus getDefault() {
        if (defaultInstance == null) {
            Class var0 = EventBus.class;
            synchronized(EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }

        return defaultInstance;
    }

這是最常用最經(jīng)典的 DoubleCheck 單例模式來(lái)創(chuàng)建 EventBus 對(duì)象。

EventBus#EventBus()

 public EventBus() {
        this(DEFAULT_BUILDER);
    }

EventBus#EventBus(EventBusBuilder builder)

 EventBus(EventBusBuilder builder) {
        this.currentPostingThreadState = new ThreadLocal<EventBus.PostingThreadState>() {
            protected EventBus.PostingThreadState initialValue() {
                return new EventBus.PostingThreadState();
            }
        };
        this.logger = builder.getLogger();
        this.subscriptionsByEventType = new HashMap();
        this.typesBySubscriber = new HashMap();
        this.stickyEvents = new ConcurrentHashMap();
        this.mainThreadSupport = builder.getMainThreadSupport();
        this.mainThreadPoster = this.mainThreadSupport != null ? this.mainThreadSupport.createPoster(this) : null;
        this.backgroundPoster = new BackgroundPoster(this);
        this.asyncPoster = new AsyncPoster(this);
        this.indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        this.subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        this.logSubscriberExceptions = builder.logSubscriberExceptions;
        this.logNoSubscriberMessages = builder.logNoSubscriberMessages;
        this.sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        this.sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        this.throwSubscriberException = builder.throwSubscriberException;
        this.eventInheritance = builder.eventInheritance;
        this.executorService = builder.executorService;
    }

同樣也是常用的 Builder 設(shè)計(jì)模式 來(lái)構(gòu)造 EventBus 對(duì)象硕蛹。

我們需要重點(diǎn)注意的幾個(gè)參數(shù)

  • HashMap 「 subscriptionsByEventType」

  • HashMap 「typesBySubscriber」

  • ConcurrentHashMap 「stickyEvents」

  • SubscriberMethodFinder 「subscriberMethodFinder」

  • Poster 「mainThreadPoster」

  • BackgroundPoster 「 backgroundPoster」

  • AsyncPoster 「asyncPoster」

具體作用我們往下分析醇疼。

二、register

1法焰、register

EventBusBuilder#register(Object subscriber)

    public void register(Object subscriber) {
      //首先獲取 subscriber 的 Class 對(duì)象
        Class<?> subscriberClass = subscriber.getClass();
      //查找所有訂閱者內(nèi)部的事件方法
        List<SubscriberMethod> subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized(this) {
            Iterator var5 = subscriberMethods.iterator();

            while(var5.hasNext()) {
                SubscriberMethod subscriberMethod = (SubscriberMethod)var5.next();
              // 調(diào)用 subscribe 分發(fā)訂閱者的事件方法
                this.subscribe(subscriber, subscriberMethod);
            }

        }
    }

從這里可以看到我們?cè)?Activity 里進(jìn)行注冊(cè)的時(shí)候秧荆,實(shí)際是把 Activity 作為訂閱者去注冊(cè)。<br />首先獲取 subscriber 的 Class 對(duì)象壶栋,然后通過(guò) findSubscriberMethods 查詢(xún)?cè)谶@個(gè)訂閱者類(lèi)里擁有 EventBus 注解的方法辰如,然后添加到 List<SubscriberMethod> subscriberMethods。然后依次調(diào)用 subscribe贵试。

2、findSubscriberMethods

SubscriberMethodFinder#findSubscriberMethods

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
     //首先看看 METHOD_CACHE 緩存中有沒(méi)有毙玻,查找過(guò)的會(huì)保存在 METHOD_CACHE 緩存 
      //詳解2.1 解釋 SubscriberMethod
        List<SubscriberMethod> subscriberMethods = (List)METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        } else {
        //一般 ignoreGeneratedIndex 默認(rèn) false 看名字應(yīng)該是通過(guò)反射來(lái)查找
            if (this.ignoreGeneratedIndex) {
                subscriberMethods = this.findUsingReflection(subscriberClass);
            } else {
                subscriberMethods = this.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;
            }
        }
    }
詳解 2.1

SubscriberMethod 是 一個(gè)包裝類(lèi)豌蟋,把方法,線程模式桑滩,事件類(lèi)梧疲,優(yōu)先級(jí),是否粘性运准,方法名稱(chēng) 包裝起來(lái)幌氮。方便我們使用。

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    String methodString;
  ···省略
  }

3胁澳、findUsingReflection

SubscriberMethodFinder#findUsingReflection

    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
      // 詳解 3.1  
      SubscriberMethodFinder.FindState findState = this.prepareFindState();
      // 詳解 3.2
        findState.initForSubscriber(subscriberClass);
            //findState.clazz 也就是 subscriberClass
        while(findState.clazz != null) {
          //詳解 3.3 把查找的信息保存在 findState 中
            this.findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }

        return this.getMethodsAndRelease(findState);
    }
詳解 3.1

FindState 是查找結(jié)果類(lèi)该互,包含 SubscriberMethod 的集合 subscriberMethods,也就是這個(gè)訂閱者 class 里所有的訂閱事件方法韭畸。還有 通過(guò) 事件類(lèi)型 為 key 保存方法的 HashMap anyMethodByEventType宇智,也就是把該事件類(lèi)型的所有方法放到這個(gè) HashMap 里蔓搞。而 subscriberClassByMethodKey 是以方法名為 key,保存訂閱者類(lèi)的 HashMap随橘。具體詳細(xì)作用需要往下繼續(xù)分析喂分。

    static class FindState {
        final List<SubscriberMethod> subscriberMethods = new ArrayList();
        final Map<Class, Object> anyMethodByEventType = new HashMap();
        final Map<String, Class> subscriberClassByMethodKey = new HashMap();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);
        Class<?> subscriberClass;
        Class<?> clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;
··· 省略
}

FindState 的創(chuàng)建運(yùn)用了數(shù)組大小為4的緩存池,當(dāng) FIND_STATE_POOL[i] 不為空的時(shí)候那么就使用這個(gè)對(duì)象机蔗,然后 FIND_STATE_POOL[i] 置為 null蒲祈。

 private SubscriberMethodFinder.FindState prepareFindState() {
        SubscriberMethodFinder.FindState[] var1 = FIND_STATE_POOL;
        synchronized(FIND_STATE_POOL) {
            for(int i = 0; i < 4; ++i) {
                SubscriberMethodFinder.FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }

            return new SubscriberMethodFinder.FindState();
        }
    }
詳解 3.2

對(duì) FindState 進(jìn)行 subscriberClass 等賦值和初始化

 void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = this.clazz = subscriberClass;
            this.skipSuperClasses = false;
            this.subscriberInfo = null;
        }
詳解 3.3

通過(guò)反射獲取 擁有 EventBus 注解的方法

    private void findUsingReflectionInSingleClass(SubscriberMethodFinder.FindState findState) {
        Method[] methods;
        try {
          //通過(guò)反射獲取訂閱者類(lèi)里所有的方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable var12) {
          //如果有權(quán)限問(wèn)題 那么就獲取 除了私有方法外的所有方法
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }

        Method[] var3 = methods;
        int var4 = methods.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Method method = var3[var5];
          //獲取方法修飾符
            int modifiers = method.getModifiers();
          //修飾符是否是 public 是否可以被忽略
            if ((modifiers & 1) != 0 && (modifiers & 5192) == 0) {
              //獲得方法的參數(shù)
                Class<?>[] parameterTypes = method.getParameterTypes();
              //我們只需要看 參數(shù)個(gè)數(shù)是 1 
                if (parameterTypes.length == 1) {
                  //獲取注解 Subscribe
                    Subscribe subscribeAnnotation = (Subscribe)method.getAnnotation(Subscribe.class);
                   //如果有
                  if (subscribeAnnotation != null) {
                    //拿到 參數(shù)的類(lèi)型 也就是 事件的類(lèi)型
                        Class<?> eventType = parameterTypes[0];
                    //詳解 3.4
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                          //把查找到的方法,事件類(lèi)型萝嘁,線程類(lèi)型讳嘱,優(yōu)先級(jí),是否粘性 放入包裝類(lèi) SubscriberMethod 中酿愧。
                          //最后添加到 subscriberMethods  
                          //循環(huán)往復(fù) 最后把所有的方法以及它的包裝類(lèi)的所有信息都放入了查找結(jié)果類(lèi) findState 沥潭。
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (this.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 (this.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");
            }
        }

    }

詳解 3.4

判斷 是否可以把 這個(gè)方法 放到訂閱方法集合。

  boolean checkAdd(Method method, Class<?> eventType) {
    //往 anyMethodByEventType 添加 key 類(lèi)型 eventType 的嬉挡,value 是 method钝鸽。
    //把事件的類(lèi)型和方法放到這個(gè)HashMap 中。 其實(shí)就是保證 同一個(gè) eventType 對(duì)應(yīng)一個(gè)方法
    //如果 key 沒(méi)有重復(fù)則 返回 null 庞钢,如果已經(jīng)有值了返回 之前的值
            Object existing = this.anyMethodByEventType.put(eventType, method);
            if (existing == null) {
                return true;
            } else {
              //如果子類(lèi)和父類(lèi)都去訂閱該事件 那么 existing 不等于 null
                if (existing instanceof Method) {
                    if (!this.checkAddWithMethodSignature((Method)existing, eventType)) {
                        throw new IllegalStateException();
                    }

                    this.anyMethodByEventType.put(eventType, this);
                }
                                //那么我們?cè)趺慈ヌ砑?重復(fù)的呢拔恰?就需要根據(jù)方法的簽名去了 詳情在下面
                return this.checkAddWithMethodSignature(method, eventType);
            }
        }
        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            this.methodKeyBuilder.setLength(0);
            this.methodKeyBuilder.append(method.getName());
            this.methodKeyBuilder.append('>').append(eventType.getName());
            String methodKey = this.methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass();
            //subscriberClassByMethodKey HashMap 是以 方法 為 key ,methodClass 為 value。
                //一個(gè)方法對(duì)應(yīng)一個(gè) methodClass
            Class<?> methodClassOld = (Class)this.subscriberClassByMethodKey.put(methodKey, methodClass);
           //class1.isAssignableFrom(class2) 判定此 Class 對(duì)象所表示的類(lèi)或接口與指定的 Class 
           //參數(shù)所表示的類(lèi)或接口是否相同基括,或是否是其超類(lèi)或超接口颜懊。
           //如果在同一個(gè)類(lèi) 不同方法名 那么返回 methodClassOld== null 直接返回 true
           //如果是 同一個(gè)方法名,那么就看看這個(gè)方法所在的類(lèi)是否有有親屬關(guān)系了风皿,如果沒(méi)有 那么就返回 false河爹,不會(huì)添加
          //如果是 同一個(gè)方法名 但是是父類(lèi)或者接口,那么返回 true桐款,最后替換 anyMethodByEventType 的方法值
    
           if (methodClassOld != null && !methodClassOld.isAssignableFrom(methodClass)) {
                this.subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            } else {
                return true;
            }
        }

一個(gè) eventType 對(duì)應(yīng)一個(gè)方法咸这,一個(gè)方法對(duì)應(yīng)一個(gè) methodClass 。<br />我們具體怎么理解 anyMethodByEventType 和 subscriberClassByMethodKey 呢魔眨?<br />我們?nèi)绾未_定同一個(gè) eventType 對(duì)應(yīng)一個(gè)方法媳维?anyMethodByEventType 負(fù)責(zé)存放這個(gè)鍵值對(duì),如果有兩個(gè)方法參數(shù)都是同一個(gè) eventType遏暴,那么就需要用 subscriberClassByMethodKey 去保證了侄刽。看一看方法名是否相同朋凉,不相同那么就替換州丹,如果相同那么就看是否是父類(lèi)的這個(gè)方法也訂閱了,如果是那么也是替換侥啤,如果不是就不會(huì)替換当叭。

到此為止我們已經(jīng)找到所有 EventBus 標(biāo)注的方法了。接下來(lái)應(yīng)該 subscribe(subscriber, subscriberMethod) 方法了盖灸∫媳睿看看這些方法是如何被注冊(cè)的。

4赁炎、subscribe

EventBus#subscribe

   private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //獲取 訂閱方法的 eventType 也就是事件 class
     Class<?> eventType = subscriberMethod.eventType;
     //創(chuàng)建 訂閱 封裝類(lèi)
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
       //  private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
     //這個(gè) Map  通過(guò) eventType 獲取 所有的訂閱集合
     //Subscription 詳解 4.1
     CopyOnWriteArrayList<Subscription> subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);
     //如果  subscriptions 為空 那么新建 并添加 到 subscriptionsByEventType
     if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList();
            this.subscriptionsByEventType.put(eventType, subscriptions);
       //如果 里面有這個(gè) 訂閱封裝類(lèi) 那么報(bào)錯(cuò) 這個(gè)類(lèi)已經(jīng)有這個(gè) 事件的訂閱了醉箕,不能重復(fù)訂閱
        } else if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
        }

        int size = subscriptions.size();
//按照 priority 優(yōu)先級(jí)來(lái)插入集合中
        for(int i = 0; i <= size; ++i) {
            if (i == size || subscriberMethod.priority > ((Subscription)subscriptions.get(i)).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
// 同一訂閱者中 typeClass 的集合 用來(lái)判斷 這個(gè)方法是否是粘性的
        List<Class<?>> subscribedEvents = (List)this.typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList();
            this.typesBySubscriber.put(subscriber, subscribedEvents);
        }

        ((List)subscribedEvents).add(eventType);
     //如果接收sticky事件,立即分發(fā)sticky事件
        if (subscriberMethod.sticky) {
          //默認(rèn)情況下 event 事件允許繼承,即默認(rèn)情況下eventInheritance==true
            if (this.eventInheritance) {
                Set<Entry<Class<?>, Object>> entries = this.stickyEvents.entrySet();
                Iterator var9 = entries.iterator();

                while(var9.hasNext()) {
                    Entry<Class<?>, Object> entry = (Entry)var9.next();
                    Class<?> candidateEventType = (Class)entry.getKey();
                  //這里就是看 eventType 是否是 candidateEventType 類(lèi) 或者 candidateEventType 的父類(lèi) 徙垫、接口
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        this.checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
              //如果不允許繼承 那么直接就是這個(gè) eventType class
                Object stickyEvent = this.stickyEvents.get(eventType);
              //這個(gè)最后走的是 postToSubscription 方法讥裤,我們下面會(huì)具體分析
                this.checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }

    }
詳解 4.1

Subscription 封裝了 subscriber 訂閱者 和 subscriberMethod 訂閱方法 ,以及這個(gè)訂閱的是否 acitive 姻报。

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    volatile boolean active;
   ···
    }

我們來(lái)看一下 subscriptionsByEventType 和 typesBySubscriber 又是兩個(gè) Map己英。

subscriptionsByEventType 是根據(jù) tpyeClass 的查找 subscriptions,也就是根據(jù)事件類(lèi)型來(lái)找 訂閱集合的吴旋。這個(gè)集合有著優(yōu)先級(jí)损肛,同一事件,不同優(yōu)先級(jí)的 subscription荣瑟。

typesBySubscriber 是跟劇 訂閱者 查找 tpyeClass治拿,也就是根據(jù)訂閱者查找其中的事件,如果有粘性的就立馬分發(fā)笆焰。

到此 register 就分析完畢劫谅,說(shuō)實(shí)話(huà)這樣分析下來(lái),腦袋里實(shí)在還是不懂這個(gè)流程嚷掠,那我們就換一下流程圖捏检,簡(jiǎn)化一下這個(gè)流程。

image.png

三不皆、post

我們?nèi)绾伟延嗛喺叩姆椒ê陀嗛喪录嚓P(guān)聯(lián)未檩,也就是事件是如何分發(fā)到事件方法的。

首先我們需要了解 「currentPostingThreadState」 在不同線程中保存 「PostingThreadState」粟焊。

private final ThreadLocal<EventBus.PostingThreadState> currentPostingThreadState;

「PostingThreadState」 是分發(fā)線程狀態(tài)冤狡,包換 事件隊(duì)列 、是否正在分發(fā)项棠、是否在主線程悲雳、是否取消了 還有訂閱分裝類(lèi) Subscription ,以及當(dāng)前事件香追。記錄著本線程中事件分發(fā)的狀態(tài)合瓢。

    static final class PostingThreadState {
        final List<Object> eventQueue = new ArrayList();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;

        PostingThreadState() {
        }
    }
    public void post(Object event) {
        EventBus.PostingThreadState postingState = (EventBus.PostingThreadState)this.currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
      //把當(dāng)前 event 添加到 eventQueue
        eventQueue.add(event);
      //如果時(shí)間沒(méi)有正在分發(fā)
        if (!postingState.isPosting) {
          //對(duì) postingState 進(jìn)行賦值
            postingState.isMainThread = this.isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }

            try {
              //依次 取出 event 并執(zhí)行 postSingleEvent 方法。
                while(!eventQueue.isEmpty()) {
                    this.postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
              //最后對(duì) postingState 做 默認(rèn)值 處理
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }

    }

通過(guò)方法命名我們知道這是處理單個(gè)事件的方法透典。

1晴楔、postSingleEvent

EventBus#postSingleEvent

    private void postSingleEvent(Object event, EventBus.PostingThreadState postingState) throws Error {
     //首先獲取這個(gè)類(lèi)的 class 對(duì)象 
       Class<?> eventClass = event.getClass();
       //是否查找到了 訂閱方法
        boolean subscriptionFound = false;
        //如果允許繼承
        if (this.eventInheritance) {
        //查找該類(lèi) 以及它的父類(lèi) 的所有 事件類(lèi)型
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
                //如果發(fā)現(xiàn)有匹配的事件類(lèi)型??
            for(int h = 0; h < countTypes; ++h) {
                Class<?> clazz = (Class)eventTypes.get(h);
                subscriptionFound |= this.postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = this.postSingleEventForEventType(event, postingState, eventClass);
        }

        if (!subscriptionFound) {
            if (this.logNoSubscriberMessages) {
                this.logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }

            if (this.sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {
                this.post(new NoSubscriberEvent(this, event));
            }
        }

    }

2顿苇、postSingleEventForEventType

    private boolean postSingleEventForEventType(Object event, EventBus.PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList subscriptions;
        synchronized(this) {
          //獲得該 eventClass 的所有 訂閱方法
            subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventClass);
        }

        if (subscriptions != null && !subscriptions.isEmpty()) {
            Iterator var5 = subscriptions.iterator();

            while(var5.hasNext()) {
              //從 方法集合中取出一個(gè) 方法
                Subscription subscription = (Subscription)var5.next();
              //給 postingState 賦值 
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;

                try {
                  //這回終于要 分發(fā)成功了
                    this.postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }

                if (aborted) {
                    break;
                }
            }

            return true;
        } else {
            return false;
        }
    }

3、postToSubscription

終于有看到這個(gè)方法税弃,在 subscrible 方法的粘性事件處理上 也是調(diào)用的這個(gè)方法纪岁,這也是我們真正分發(fā)的方法。

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
       //首先判斷 是哪種 threadMode 模式 運(yùn)行
       switch(subscription.subscriberMethod.threadMode) {
        case POSTING:
        //詳解 3.1
            this.invokeSubscriber(subscription, event);
            break;
        case MAIN:
         //詳解 3.2
            if (isMainThread) {
                this.invokeSubscriber(subscription, event);
            } else {
                this.mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED:
            if (this.mainThreadPoster != null) {
                this.mainThreadPoster.enqueue(subscription, event);
            } else {
                this.invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND:
         //詳解 3.3
            if (isMainThread) {
                this.backgroundPoster.enqueue(subscription, event);
            } else {
                this.invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
        //詳解 3.4
            this.asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }

    }
詳解 3.1

EventBus#invokeSubscriber

    void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException var4) {
            this.handleSubscriberException(subscription, event, var4.getCause());
        } catch (IllegalAccessException var5) {
            throw new IllegalStateException("Unexpected exception", var5);
        }

    }

最后我們發(fā)現(xiàn) invokeSubscriber 方法實(shí)際是通過(guò) subscription 的持有的 method 的引用通過(guò)反射的方法则果,把 訂閱者 subscriber 和 事件 event 填入幔翰,真正調(diào)用的就是 subscriber.xxx(event)。也就是 activity.xxx(event)西壮。

饒了一大圈遗增,其實(shí)也就是把 訂閱者 和 事件的 引用保存起來(lái),查找方法款青,通過(guò)反射進(jìn)行調(diào)用做修。真是原理很簡(jiǎn)單,實(shí)現(xiàn)很蛋疼抡草,不把你繞暈是不行的缓待。

詳解 3.2

如果 是在主線程中,isMainThread == true渠牲,直接 invokeSubscriber 旋炒。<br />如果 false ,那么就需要 倒一手了签杈。其實(shí) HandlerPoster 就是 一個(gè) Handler 瘫镇, 并且它的 Lopper 是主線程的Looper 。這樣就是通過(guò) Handler 答姥,添加到主線程了铣除,然后執(zhí)行 invokeSubscriber 。這么看切換線程原理還是 Handler鹦付。

HandlerPoster#enqueue

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

        }
    }
詳解 3.3

BackgroundPoster 和 主線程的 HandlerPoster 不通尚粘,它是一個(gè) Runnable 線程。和主線程 HandlerPoster 不同的是它會(huì)把 queue 的所有 pendingPost 都去執(zhí)行敲长。

final class BackgroundPoster implements Runnable, Poster {
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    private volatile boolean executorRunning;

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

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

        }
    }

    public void run() {
        try {
            while(true) {
                PendingPost pendingPost = this.queue.poll(1000);
                if (pendingPost == null) {
                    synchronized(this) {
                        pendingPost = this.queue.poll();
                        if (pendingPost == null) {
                            this.executorRunning = false;
                            return;
                        }
                    }
                }

                this.eventBus.invokeSubscriber(pendingPost);
            }
        } catch (InterruptedException var9) {
            this.eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", var9);
        } finally {
            this.executorRunning = false;
        }
    }
}

詳解 3.4

AsyncPoster 是一個(gè) Runnalbe郎嫁。是通過(guò)線程池產(chǎn)生新的線程,最后執(zhí)行 invokeSubscriber 方法祈噪。和 BackgroundPoster 不同的是 一次只取一個(gè) PendingPost泽铛。

class AsyncPoster implements Runnable, Poster {
    private final PendingPostQueue queue;
    private final EventBus eventBus;

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

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

    public void run() {
        PendingPost pendingPost = this.queue.poll();
        if (pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        } else {
            this.eventBus.invokeSubscriber(pendingPost);
        }
    }
}
        //最后還是走的 invokeSubscriber 方法
    void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            this.invokeSubscriber(subscription, event);
        }

    }

最后也要來(lái)一個(gè)流程圖來(lái)總結(jié)下 post 的流程。

image.png

四辑鲤、 unregister

解綁訂閱者和訂閱事件盔腔。

    public synchronized void unregister(Object subscriber) {
      //獲取 該 訂閱者 的所有 訂閱事件
        List<Class<?>> subscribedTypes = (List)this.typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            Iterator var3 = subscribedTypes.iterator();

            while(var3.hasNext()) {
                Class<?> eventType = (Class)var3.next();
              //挨個(gè) 解綁 訂閱者 和 訂閱事件的關(guān)系
                this.unsubscribeByEventType(subscriber, eventType);
            }
                        //最后把這個(gè) 訂閱者 移出 該 map
            this.typesBySubscriber.remove(subscriber);
        } else {
            this.logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }

    }
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    //獲取 這個(gè)訂閱事件的 所有訂閱者
        List<Subscription> subscriptions = (List)this.subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();

            for(int i = 0; i < size; ++i) {
                Subscription subscription = (Subscription)subscriptions.get(i);
                //判斷 是否是這個(gè)訂閱者 subscription 置 flase ,然后 移除 該集合
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    --i;
                    --size;
                }
            }
        }

    }

總結(jié)

一、regist

1弛随、遍歷所有 EventBus 的訂閱事件瓢喉。<br />2、把 封裝訂閱者加入 以事件類(lèi)型為 key 舀透,所有封裝訂閱者的集合為 values 的 Map 中栓票。詳細(xì)見(jiàn)注釋。<br />3盐杂、把訂閱事件 添加到 以 「subscriber」訂閱者為 key,「subscribedEvents」訂閱事件集合為 value 的 Map 中哆窿。<br />4链烈、如果訂閱了粘性事件的訂閱者,那么會(huì) 粘性事件集合中獲取之前的粘性事件挚躯,然后相應(yīng)這些粘性事件强衡。

注釋?zhuān)?lt;br />把 「subscriber」和 「subscriberMethod」封裝成 「Subscription」 封裝訂閱者。通過(guò) 訂閱事件的 「SubscriberMethod」 獲取 「eventType」码荔,以 eventType 事件類(lèi)型為 key 漩勤,封裝訂閱者集合(subscriptions)為 value 的 Map 「subscriptionsByEventType」。并把這個(gè) Subscription 添加到 subscriptions 中缩搅。

二越败、post

1、獲取該線程下的事件隊(duì)列硼瓣。<br />2究飞、把要發(fā)送的事件添加到隊(duì)列中。<br />3堂鲤、根據(jù)訂閱事件 查找所有 封裝訂閱者亿傅。<br />4、根據(jù)訂閱方法的執(zhí)行模式瘟栖,在對(duì)應(yīng)的線程中通過(guò)反射執(zhí)行訂閱者的訂閱方法葵擎。

三、unregist

1半哟、首先 獲取訂閱者的所有訂閱事件酬滤。<br />2、遍歷 訂閱事件 <br />3寓涨、根據(jù) 訂閱事件獲取 訂閱者的集合敏晤。<br />4、判斷 該訂閱者 是否在 封裝訂閱者集合 「subscriptions」中缅茉,把這個(gè)訂閱者從 subscriptions 中移除嘴脾。<br />5、最后 把訂閱者 從「typesBySubscriber」中移除。

最后

「云開(kāi)方見(jiàn)日译打,潮盡爐峰出耗拓。」——戴叔倫

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奏司,一起剝皮案震驚了整個(gè)濱河市乔询,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌韵洋,老刑警劉巖竿刁,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異搪缨,居然都是意外死亡食拜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)副编,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)负甸,“玉大人,你說(shuō)我怎么就攤上這事痹届∩氪” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵队腐,是天一觀的道長(zhǎng)蚕捉。 經(jīng)常有香客問(wèn)我柴淘,道長(zhǎng)鱼冀,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任悠就,我火速辦了婚禮千绪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梗脾。我一直安慰自己荸型,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布炸茧。 她就那樣靜靜地躺著瑞妇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梭冠。 梳的紋絲不亂的頭發(fā)上辕狰,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音控漠,去河邊找鬼蔓倍。 笑死悬钳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的偶翅。 我是一名探鬼主播默勾,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼聚谁!你這毒婦竟也來(lái)了母剥?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤形导,失蹤者是張志新(化名)和其女友劉穎环疼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體朵耕,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炫隶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了憔披。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片等限。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爸吮,死狀恐怖芬膝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情形娇,我是刑警寧澤锰霜,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站桐早,受9級(jí)特大地震影響癣缅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哄酝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一友存、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陶衅,春花似錦屡立、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至罩句,卻和暖如春焚刺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背门烂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工乳愉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓匾委,卻偏偏與公主長(zhǎng)得像拖叙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赂乐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • EventBus源碼分析 Android開(kāi)發(fā)中我們最常用到的可以說(shuō)就是EventBus了薯鳍,今天我們來(lái)深入研究一下E...
    BlackFlag閱讀 509評(píng)論 3 4
  • 前面對(duì)EventBus 的簡(jiǎn)單實(shí)用寫(xiě)了一篇,相信大家都會(huì)使用挨措,如果使用的還不熟挖滤,或者不夠6,可以花2分鐘瞄一眼:h...
    gogoingmonkey閱讀 317評(píng)論 0 0
  • 簡(jiǎn)介 前面我學(xué)習(xí)了如何使用EventBus浅役,還有了解了EventBus的特性斩松,那么接下來(lái)我們一起來(lái)學(xué)習(xí)EventB...
    eirunye閱讀 465評(píng)論 0 0
  • EventBus源碼分析(一) EventBus官方介紹為一個(gè)為Android系統(tǒng)優(yōu)化的事件訂閱總線,它不僅可以很...
    蕉下孤客閱讀 4,018評(píng)論 4 42
  • EventBus是在Android中使用到的發(fā)布-訂閱事件總線框架觉既,基于觀察者模式惧盹,將事件的發(fā)送者和接收者解耦,簡(jiǎn)...
    BrotherTree閱讀 407評(píng)論 0 1