EventBus源碼解析

(1)eventbus的使用

為了方便分析EventBus的源碼逛揩,這里我們先整個demo出來辩稽,源碼如下:

public class MainActivity extends AppCompatActivity {

    private TextView tvMessage;
    private View btnSecond;
    private Button btnRegister;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);

        tvMessage = findViewById(R.id.tv_message);
        btnSecond = findViewById(R.id.btn_second);
        btnRegister = findViewById(R.id.tv_register);

        btnRegister.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {

            }
        });
        btnSecond.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
       loadData("http://www.baidu.com");
    }

    public void loadData(final String url){
        new Thread(){
            @Override
            public void run() {
                super.run();
                String json = "message from MainActivity";
                MessageEvent messageEvent = new MessageEvent("recode",json,"msg");
                //在子線程當中發(fā)布類給主線程
                // EventBus.getDefault().post(json);
                EventBus.getDefault().post(messageEvent);
            }
        }.start();
    }


  //  @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)//MAIN代表主線程
   @Subscribe(threadMode = ThreadMode.MAIN,sticky = false)
    public void receiveMessage(MessageEvent messageEvent){//該方法名可更改,不影響任何東西各谚。
        //在主線程中獲取子線程發(fā)送來的消息設(shè)置到TextView中
        tvMessage.setText(messageEvent.getResult());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}

(2)EventBus的register過程

  • EventBus的初始化
 public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

可以看出:EventBus調(diào)用getDefault方法進行初始化憔四,并且使用了雙重否定的單例模式了赵。

  • EventBus調(diào)用register方法進行事件訂閱
   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:訂閱者對象柿汛,對應(yīng)demo中的MainActivity
  • SubscriberMethod:是我們在Activity中定義的訂閱方法的一個描述類,里面保存了訂閱方法的信息妓羊,其實就是我們在Activity中定義的用@Subscriber注解修飾的receiveMessage(MessageEvent)方法。這里我截取了SubscriberMethod的成員變量信息净刮,如下所示:
 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;
    }

method:方法名
ThreadMode:注解名稱
eventType:消息類型的字節(jié)碼對象,對應(yīng)demo中MessageEvent的class對象
priority:注解中priority屬性暑认,表示方法執(zhí)行的優(yōu)先級

  • EventBus是如何找到subscriberMethod的集合的呢困介?

subscriberMethodFinder調(diào)用findSubscriberMethods(subscriberClass)方法找到了Subscriber對象(MainActivity)中所有訂閱方法信息的集合。

那么findSubscriberMethods是如何找到SubscriberMethod的呢蘸际?

我們接著往下看SubscriberMethodFinder的findSubscriberMethods方法座哩,代碼如下所示:

    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:EventBus對Subscriber訂閱者的訂閱方法做的一個緩存,它是一個Map對象粮彤,key是Subscriber對象根穷,因為Subscriber對象可能有多個訂閱方法导坟,所以value是Subscriber對應(yīng)的訂閱方法的集合屿良。

可以看出EventBus先會從緩存中拿Subscriber對應(yīng)的SubscriberMethod的集合,如果緩存不為空乍迄,直接從緩存中獲取管引。

  • ignoreGeneratedIndex:這個參數(shù)默認是為false,表示使用@Subscribe注解闯两,EventBus3.0版本后默認使用該注解來表示訂閱方法褥伴。而在EventBus3.0之前只能使用寫死的方法定義訂閱方法,這樣非常容易出錯漾狼。真正的獲取訂閱方法集合的方法其實是findUsingInfo(subscriberClass)方法重慢。

findUsingInfo的源碼如下所示:

 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

首先會執(zhí)行prepareFindState方法去獲取FindState,代碼如下:

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

FIND_STATE_POOL:是一個最近使用且長度為4的FindState數(shù)組逊躁,目的是用來EventBus緩存FindState信息似踱,提升eventBus的運行效率的。

  • FindState對象是什么稽煤?
 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類就是一個保存將要查找的訂閱方法信息的類轧简。其主要成員變量如下:

  • subscriberMethods :SubScriber訂閱者(對應(yīng)demo中MainActivity)的所有訂閱方法的集合。

  • anyMethodByEventType :一個用來保存eventType(對應(yīng)demo中的EventMessage)和其對應(yīng)的method匾二。

  • subscriberClassByMethodKey :一個map對象哮独,key是一個訂閱方法名稱和EventType參數(shù)構(gòu)成的字符串,value為訂閱方法的class對象察藐。

  • subscriberClass和class:訂閱者類的class字節(jié)碼對象

  • 如何獲取subscriber的訂閱方法皮璧?

    private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

subscriberInfoIndexes 不為空會調(diào)用getSubscriberInfo方法獲取SubscriberInfo對象,SubscriberInfo對象包括了Subscriber和訂閱方法的信息分飞。后面我們發(fā)現(xiàn)SubscriberInfo是通過index.getSubscriberInfo()方法來得到的悴务。那么index指的是什么呢?

3.0版本中,EventBus提供了一個EventBusAnnotationProcessor注解處理器來在編譯期通過讀取@Subscribe()注解并解析,
處理其中所包含的信息,然后生成java類來保存所有訂閱者關(guān)于訂閱的信息,這樣就比在運行時使用反射來獲得這些訂閱者的
信息速度要快.我們可以參考EventBus項目里的EventBusPerformance這個例子,編譯后我們可以在build文件夾里找到這個類MyEventBusIndex 類譬猫,前面的index就屬于MyEventBusIndex對象類型

建議用git拉下EventBus的源碼惨寿,然后搜索EventBusAnnotationProcessor這個類邦泄,其源碼比較多,這里我們看看它的createInfoIndexFile方法裂垦,其源碼如下所示:

  private void createInfoIndexFile(String index) {
        BufferedWriter writer = null;
        try {
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
            int period = index.lastIndexOf('.');
            String myPackage = period > 0 ? index.substring(0, period) : null;
            String clazz = index.substring(period + 1);
            writer = new BufferedWriter(sourceFile.openWriter());
            if (myPackage != null) {
                writer.write("package " + myPackage + ";\n\n");
            }
            writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
            writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
            writer.write("import java.util.HashMap;\n");
            writer.write("import java.util.Map;\n\n");
            writer.write("/** This class is generated by EventBus, do not edit. */\n");
            writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
            writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
            writer.write("    static {\n");
            writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
         
            writeIndexLines(writer, myPackage);//把用了Subscriber注解的方法和方法所在的類信息拼湊起來
            writer.write("    }\n\n");
            writer.write("    private static void putIndex(SubscriberInfo info) {\n");
            writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
            writer.write("    }\n\n");
            writer.write("    @Override\n");
            writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
            writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
            writer.write("        if (info != null) {\n");
            writer.write("            return info;\n");
            writer.write("        } else {\n");
            writer.write("            return null;\n");
            writer.write("        }\n");
            writer.write("    }\n");
            writer.write("}\n");
        } catch (IOException e) {
            throw new RuntimeException("Could not write source for " + index, e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    //Silent
                }
            }
        }
    }

createInfoIndexFile方法其實就是在創(chuàng)建一個MyEventBusIndex.class文件顺囊,其中writeIndexLines方法是在把用了Subscriber注解的方法和方法所在的類信息拼湊起來,writeIndexLines方法的源碼如下所示:

    private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException {
        for (TypeElement subscriberTypeElement : methodsByClass.keySet()) {
            if (classesToSkip.contains(subscriberTypeElement)) {
                continue;
            }

            String subscriberClass = getClassString(subscriberTypeElement, myPackage);
            if (isVisible(myPackage, subscriberTypeElement)) {
                writeLine(writer, 2,
                        "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,",
                        "true,", "new SubscriberMethodInfo[] {");
                List<ExecutableElement> methods = methodsByClass.get(subscriberTypeElement);
                writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage);
                writer.write("        }));\n\n");
            } else {
                writer.write("        // Subscriber not visible to index: " + subscriberClass + "\n");
            }
        }
    }

下面再來看看EventBusAnnotationProcessor注解處理類生成的MyEventBusIndex這個類都長什么樣吧蕉拢,可以通過build EventBusPerformance這個model來生成它特碳。

public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscribeClassEventBusMainOrdered.class,
                true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEvent", TestEvent.class, ThreadMode.MAIN_ORDERED),
        }));

        putIndex(new SimpleSubscriberInfo(TestRunnerActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEventMainThread", TestFinishedEvent.class, ThreadMode.MAIN),
        }));

        putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscribeClassEventBusBackground.class,
                true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEventBackgroundThread", TestEvent.class, ThreadMode.BACKGROUND),
        }));

        putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscribeClassEventBusMain.class,
                true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEventMainThread", TestEvent.class, ThreadMode.MAIN),
        }));

        putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.SubscribeClassEventBusDefault.class,
                true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEvent", TestEvent.class),
        }));

        putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscriberClassEventBusAsync.class,
                true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEventAsync", TestEvent.class, ThreadMode.ASYNC),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

可以看出MyEventBusIndex這個類已經(jīng)把我們定義的訂閱方法信息全都用一個map保存起來了,key為Subscriber的字節(jié)碼類晕换,value為訂閱方法信息類午乓。后面也就不奇怪,我們可以通過迭代直接得到訂閱方法的信息了闸准。

如果EventBus沒有拿到MyEventBusIndex對象攜帶的訂閱方法信息的話益愈,那么將通過Subscriber對象手動解析帶有@subscribe注解的訂閱方法,當然這種方法效率太低了夷家,其實是一種容錯處理蒸其。這個解析過程便是通過findUsingReflectionInSingleClass實現(xiàn)的,如下所示:

  private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        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) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

  • 訂閱方法注冊過程

前面我們拿到了訂閱方法以及訂閱對象的信息后,并保持在SubscriberMethod集合中,后面會迭代這個集合潮酒,然后依次執(zhí)行subscribe方法。subscribe方法的源碼如下所示:

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

        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(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);
            }
        }
    }

subscribe()方法其實主要就干了這么幾件事:

  • 對消息進行優(yōu)先級排序

  • 緩存subscriber method的信息
    subscriptionsByEventType這個Map對象的值就是用來緩存訂閱方法的信息的靠汁,其中key為EventType的class對象,value為Subscription對象的集合闽铐,而Subscription對象的成員變量就是訂閱者對象Subscriber以及訂閱方法SubscriberMethod蝶怔,這個map對象在后面發(fā)送消息時會用到,當要發(fā)送消息時兄墅,其實就是迭代這個對象添谊,然后利用發(fā)射執(zhí)行訂閱方法。

  • 如果有sticky消息察迟,直接發(fā)送。也可以得知sticky消息在注冊后是可以
    執(zhí)行的耳高。

整個注冊的大致流程如下:

eventbus注冊流程.png

(2)發(fā)送消息和接收消息

由于sticky消息的發(fā)送最終也是執(zhí)行post方法扎瓶,這里只拿post方法來做分析,EventBus的post方法的源碼如下所示:

  public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

這個方法主要用來泌枪,判斷消息是否已經(jīng)發(fā)送概荷,方法執(zhí)行到底是否在主線程中,消息是否已經(jīng)取消碌燕,并且用EventType保存了如果符合要求误证,則程序繼續(xù)往下執(zhí)行postSingleEvent方法继薛,然后是各種判斷,接著會執(zhí)行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;
    }

這個方法會拿出注冊時緩存訂閱方法的相關(guān)信息subscriptionsByEventType愈捅,并迭代這個Map對象遏考,取出訂閱方法的信息,并最終執(zhí)行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 MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(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);
        }
    }

看到這里是不是有種似曾相識的感覺呢灌具?沒錯就是根據(jù)注解中threadMode的值,判斷方法在哪個線程中執(zhí)行譬巫,無論是在主線程還是子線程中執(zhí)行咖楣,最終都會invokeSubscriber方法,其實就是利用發(fā)射執(zhí)行Subscriber method芦昔,所以EventBus的post()方法執(zhí)行后诱贿,最終會執(zhí)行Subscriber method。

  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);
        }
    }
  • POSTING:Subscriber和Subscriber Method在同一個線程中執(zhí)行

  • MAIN:Subscriber Method將在主線程中執(zhí)行咕缎,如果在主線程中直接執(zhí)行Subscriber Method珠十,如果在子線程中使用handler進行消息發(fā)送,并在主線程中執(zhí)行锨阿。

  • MAIN_ORDERED:主線程中按順序執(zhí)行Subscriber Method宵睦。

  • BACKGROUND:如果post方法發(fā)送消息在子線程中,那么直接執(zhí)行Subscriber method墅诡;如果post方法發(fā)送消息是在主線程中壳嚎,將會在子線程中執(zhí)行Subscriber method。

  • ASYNC:無論是在主線程還是子線程中發(fā)送消息末早,那么都講會子線程中執(zhí)行Subscriber method


    EventBus發(fā)送消息的過程.png

(3) EventBus unRegister過程

unregister方法的源碼如下:

 /** 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 {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

把之前Subscriber注冊時保存下來的訂閱方法信息刪除烟馅,然后執(zhí)行
unsubscribeByEventType方法,其代碼如下所示:

   private void unsubscribeByEventType(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--;
                }
            }
        }
    }

循環(huán)查找subScription對象并把它的active屬性改成false然磷,最后刪除subscription對象郑趁。

---------------end-----------------

如果文章對你有幫助的話,記得點一個贊哦姿搜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末寡润,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子舅柜,更是在濱河造成了極大的恐慌梭纹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件致份,死亡現(xiàn)場離奇詭異变抽,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門绍载,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诡宗,“玉大人,你說我怎么就攤上這事击儡∷郑” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵曙痘,是天一觀的道長芳悲。 經(jīng)常有香客問我,道長边坤,這世上最難降的妖魔是什么名扛? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮茧痒,結(jié)果婚禮上肮韧,老公的妹妹穿的比我還像新娘。我一直安慰自己旺订,他們只是感情好弄企,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著区拳,像睡著了一般拘领。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上樱调,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天约素,我揣著相機與錄音,去河邊找鬼笆凌。 笑死圣猎,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的乞而。 我是一名探鬼主播送悔,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼爪模!你這毒婦竟也來了欠啤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤屋灌,失蹤者是張志新(化名)和其女友劉穎洁段,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體声滥,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了落塑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纽疟。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖憾赁,靈堂內(nèi)的尸體忽然破棺而出污朽,到底是詐尸還是另有隱情,我是刑警寧澤龙考,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布蟆肆,位于F島的核電站,受9級特大地震影響晦款,放射性物質(zhì)發(fā)生泄漏炎功。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一缓溅、第九天 我趴在偏房一處隱蔽的房頂上張望蛇损。 院中可真熱鬧,春花似錦坛怪、人聲如沸淤齐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽更啄。三九已至,卻和暖如春居灯,著一層夾襖步出監(jiān)牢的瞬間祭务,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工穆壕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留待牵,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓喇勋,卻偏偏與公主長得像缨该,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子川背,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

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