EventBus源碼全流程解讀

目錄

  • EventBus優(yōu)缺點(diǎn)

  • EventBus基本用法

  • EventBus源碼解析

一、EventBus優(yōu)缺點(diǎn)對比

優(yōu)點(diǎn):
1壶谒、是一個輕量級的事件總線橱脸,使用方便
2、去除應(yīng)用中大量的回調(diào)抱冷,能一定程度解耦各組件

缺點(diǎn):
1崔列、代碼可讀性降低,大量的事件使代碼解耦的同時旺遮,聯(lián)系也變得弱了
2赵讯、不支持跨進(jìn)程通訊(廣播支持)

二、EventBus使用

首先使用別人家的東西第一步導(dǎo)包:

implementation 'org.greenrobot:eventbus:3.1.1'

EventBus使用相對簡單耿眉,github下面就有使用步驟边翼,我們直接參照


EventBus官方使用步驟說明.png

1.定義傳遞的時間對象,該對象就是步驟2中接收的對象鸣剪,也是步驟3中發(fā)送的事件
2.(1)定義接收事件方法(即訂閱方法)组底,該方法用注解@Subscribe修飾丈积,并通過threadMode指定其分發(fā)到的線程 (2)在定義接收方法的類中(Android中一般為activity、fragment或service)注冊與解注冊EventBus
3.在任何地方通過post方法發(fā)送你的事件
通過以上三個步驟就可以使用EventBus進(jìn)行事件傳遞

三债鸡、源碼分析

在分析源碼之前我們有幾個問題需要拋出
1江滨、EventBus是如何確定哪些方法是訂閱方法的
2、EventBus是如何做線程切換的
3厌均、EventBus為什么不支持跨進(jìn)程
如果讀完這篇源碼分析能解決以上問題就足夠了

1.EventBus對象

EventBus.java

static volatile EventBus defaultInstance;
//雙重檢查鎖獲取單例對象
public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

EventBus.getDefault()通過雙重檢查鎖獲取單例對象唬滑,并通過volatile關(guān)鍵字保證單例對象的可見性

2.register與unregister

(1) register

/**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * <p/>
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        //1、SubscriberMethod為已訂閱的方法莫秆,這里通過類對象查找到該類所有訂閱方法  
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        //2间雀、遍歷該類所有已訂閱方法,并訂閱  
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

上面代碼也很好理解镊屎,
(1)根據(jù)類對象獲得該類中定義的訂閱方法信息
(2)遍歷所有訂閱方法執(zhí)行訂閱
下面針對這兩個問題我們具體進(jìn)去看看
SubscriberMethodFinder.java

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

這里主要根據(jù)ignoreGeneratedIndex標(biāo)志位判斷調(diào)用哪個方法獲取訂閱方法惹挟,ignoreGeneratedIndex標(biāo)志位使用的是EventBusBuilder的默認(rèn)實(shí)例,EventBusBuilder的ignoreGeneratedIndex默認(rèn)為false,因此這里會執(zhí)行findUsingInfo(subscriberClass)

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        //1缝驳、循環(huán)遍歷該類及其父類的方法
        while (findState.clazz != null) {
            //獲取已訂閱信息緩存
            findState.subscriberInfo = getSubscriberInfo(findState);
            //2连锯、判斷訂閱方法是否為空,為空通過反射獲取訂閱方法用狱;不為空直接使用緩存
            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);
    }

這里通過FindState對象保存需要的信息运怖,通過遍歷該類及其所有父類獲取所有訂閱方法,訂閱信息如已存在于緩存中夏伊,直接取出使用;如果為緩存中沒有摇展,使用反射獲取。下面我們著重看看反射獲取訂閱方法的相關(guān)內(nèi)容

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) {
            //1溺忧、判斷方法必須是public修飾咏连,且不是static也不是abstract修飾的
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //2鲁森、獲取方法入?yún)⒙⒍袛嗳雲(yún)⒅挥幸粋€,繼續(xù)執(zhí)行(表示訂閱方法只能有一個入?yún)ⅲ?                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                    //3痛垛、獲取注解草慧,判斷注解不為空則繼續(xù)執(zhí)行(表示訂閱方法必須由Subscribe注解)
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            //獲取直接中threadMode參數(shù),該參數(shù)為訂閱方法執(zhí)行的線程定義
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //4榜晦、以上全部符合要求乾胶,將信息保存到findState中
                            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");
            }
        }
    }

通過findUsingReflectionInSingleClass方法我們可以看到EventBus對訂閱方法的約束:
1抖剿、訂閱方法必須是public修飾的脑融,且不能用static、abstract修飾
2缩宜、訂閱方法的參數(shù)只能是一個肘迎,即事件對象
3、訂閱方法必須有@ Subscribe注解 锻煌,threadMode默認(rèn)為POSTING

分析完訂閱方法的獲取妓布,我們具體看看這些方法是如何訂閱的

    //根據(jù)事件類型(eventType),保存所有eventType的訂閱方法
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    //根據(jù)訂閱對象(subscriber)宋梧,保存該訂閱對象的所有事件
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        //訂閱方法的封裝對象
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //將所有事件類型的訂閱方法保存在一個集合中
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        /**
         *  1匣沼、判斷該事件是否已有存儲訂閱方法信息的容器;
         *  沒有則創(chuàng)建容器,并將容器存入subscriptionsByEventType中捂龄;
         *  若存在判斷該訂閱方法(newSubscription)是否已在容器中释涛,已在拋出重復(fù)注冊異常
         */
        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();
        //2、根據(jù)優(yōu)先級將訂閱方法(newSubscription)插入容器對用的位置
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
        //3倦沧、根據(jù)注冊對象subscriber保存該對象所有事件(實(shí)際subscribedEvents緩存的信息代表該注冊對象subscriber是否被注冊)
        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方法總共有做了幾件事:
1唇撬、通過eventType將該eventType下所有訂閱方法保存在subscriptionsByEventType中
2、通過訂閱對象將該訂閱對象所擁有的所有eventType對象保存在typesBySubscriber中
3展融、判斷是否是粘性事件并做對應(yīng)的處理(這里我們不做分析)

看到這里肯定有很多的疑惑:
1窖认、subscriptionsByEventType這個map是做什么的?
2告希、typesBySubscriber這個map又是做什么的耀态?
這里我們先揭曉答案:
1、subscriptionsByEventType實(shí)際是通過eventType保存該eventType所有的訂閱方法暂雹,這里理解為實(shí)際的訂閱;待事件分發(fā)時再根據(jù)eventType從subscriptionsByEventType中獲取訂閱方法進(jìn)行分發(fā)(后面post中會分析)
2创夜、typesBySubscriber通過注冊對象保存該注冊對象所有的事件杭跪;這里保存代表為實(shí)際注冊,待解注冊時驰吓,再講該注冊對象的eventType從typesBySubscriber中移除涧尿,這個在unregister中可以體現(xiàn)

(2) unregister
接下來我們就來看看unregister方法:

/** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        //1、獲取緩存中注冊對象所有事件類型檬贰,遍歷并解訂閱事件
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            //全部事件解訂閱后姑廉,刪除typesBySubscriber中的類對象,實(shí)際這里表示解注冊
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

分析代碼可以知道翁涤,解注冊實(shí)際做了兩件事
1桥言、解訂閱所有的訂閱事件,及遍歷執(zhí)行unsubscribeByEventType()方法
2萌踱、訂閱類移除map列表中,即typesBySubscriber.remove(subscriber)
unsubscribeByEventType()方法通過名稱已經(jīng)很明顯;無非就是將注冊時保存在subscriptionsByEventType中的訂閱方法移除号阿;具體代碼貼出并鸵,但并沒有太值得閱讀的地方

/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    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--;
                }
            }
        }
    }

3.post方法

剛剛已經(jīng)分析register方法,發(fā)現(xiàn)register其實(shí)最主要的就是將所有已注冊對象中的訂閱方法保存在subscriptionsByEventType這個map中扔涧,那post自然就是遍歷subscriptionsByEventType這個map然后執(zhí)行對應(yīng)的分發(fā)园担。

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
    /** Posts the given event to the event bus. */
    public void post(Object event) {
        //1、使用ThreadLocal獲取當(dāng)前線程參數(shù)
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        //將事件加入List隊(duì)列中
        eventQueue.add(event);
        //2枯夜、判斷當(dāng)前線程post狀態(tài)
        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                //3弯汰、postSingleEvent處理單個事件
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                //4、恢復(fù)post線程狀態(tài)
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

這段代碼主要是判斷當(dāng)前線程post狀態(tài)湖雹,如果有正在分發(fā)中的事件咏闪,則將新事件置入事件池排隊(duì)等待執(zhí)行;如果沒有劝枣,則將事件加入隊(duì)列并執(zhí)行汤踏。其核心代碼為postSingleEvent(eventQueue.remove(0), postingState) 所以我們繼續(xù)看看postSingleEvent做了些什么事

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;//該屬性判斷是否存在待分發(fā)事件的訂閱方法
        if (eventInheritance) {//eventInheritance為默認(rèn)Builder中的值,默認(rèn)為true
            //找到當(dāng)前待分發(fā)事件的所有事件類型(這里包括父類舔腾、接口類等)
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                //1溪胶、postSingleEventForEventType通過事件類型查找是否有對應(yīng)的訂閱方法
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        //2、如果沒有找到對應(yīng)的訂閱方法稳诚,發(fā)送一個默認(rèn)事件
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

1哗脖、判斷是否找到待分發(fā)事件的訂閱方法,找到則分發(fā)事件扳还,其核心代碼為subscriptionFound |= postSingleEventForEventType(event, postingState, clazz)
2才避、未找到則默認(rèn)發(fā)送一個默認(rèn)的事件,post(new NoSubscriberEvent(this, event))

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            //1氨距、在subscriptionsByEventType中獲取該事件對應(yīng)訂閱方法的集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            //2桑逝、遍歷集合,并執(zhí)行分發(fā)事件至具體的已訂閱方法中
            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;
    }

這里的主要邏輯如下
1俏让、通過事件類對象在subscriptionsByEventType這個map中取出該事件的所有訂閱類集合楞遏,subscriptionsByEventType中的訂閱方法集合是在注冊是添加的,我們在分析register源碼時已經(jīng)分析了首昔;
2寡喝、取出該事件訂閱方法合集之后就是遍歷所有的訂閱方法并分發(fā),該過程核心代碼為:postToSubscription(subscription, event, postingState.isMainThread)
說了那么久才真正的進(jìn)入post最核心的地方--事件分發(fā)勒奇,到目前為止我們知道post進(jìn)入時會根據(jù)當(dāng)前線程獲取一個緩存信息類postingState對象预鬓,其不同線程有通的隊(duì)列處理消息分發(fā);但是我們都知道EventBus中是幫我們做了線程切換的赊颠,我們可以通過@ Subscribe注解的threadMode屬性指定訂閱方法執(zhí)行的線程格二;那這一塊的具體邏輯應(yīng)該就是在postToSubscription中劈彪,所以帶著問題我們一起進(jìn)入看看:

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ìn)入就可以看到代碼對threadMode進(jìn)行判斷:
PSOTING:直接反射調(diào)用訂閱方法;該模式表示在哪個線程發(fā)布事件就在哪個線程處理
MAIN:如果當(dāng)前post線程為主線程直接反射調(diào)用方法(防止主線程阻塞)蟋定,如果post線程不是主線程粉臊,則調(diào)用mainThreadPoster排隊(duì)處理;該模式表示在主線程調(diào)用訂閱方法
MAIN_ORDERED:因?yàn)閙ainThreadPoster不會為null所以一直會排隊(duì)處理驶兜,并且會回調(diào)到主線程處理扼仲;該模式表示在主線程中排隊(duì)處理(即等待上一個時間處理后再發(fā)送下一個事件)
BACKGROUND:如果當(dāng)前post線程為主線程,開啟一個新的后臺線程處理分發(fā)抄淑,如果當(dāng)前post線程不為主線程屠凶,則直接反射調(diào)用;該模式表示事件一直在后臺線程中處理
ASYNC:由asyncPoster排隊(duì)處理肆资;該模式表示不管post線程是否為主線程矗愧,都會新開一個異步線程處理

這邊可以總結(jié)得出,部分情況直接反射調(diào)用訂閱方法郑原;部分根據(jù)情況開啟對應(yīng)的線程處理唉韭;如mainThreadPoster實(shí)際是Handler子類,通過handler機(jī)制切換回主線程犯犁,backgroundPoster属愤、asyncPoster實(shí)際實(shí)現(xiàn)了Runable接口,在子線程中執(zhí)行酸役;他們主要的工作只是線程切換住诸,切換后最終都會通過EventBus的反射方法地調(diào)用訂閱方法 eventBus.invokeSubscriber(pendingPost)
反射方法如下:
其中帶一個入?yún)⒌姆瓷浞椒ň褪枪┚€程切換后調(diào)用的反射方法

/**
     * Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions
     * between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the
     * subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the
     * live cycle of an Activity or Fragment.
     */
    void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            invokeSubscriber(subscription, event);
        }
    }

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

至此我們的源碼分析就結(jié)束了,現(xiàn)在讓我們回到開始的那幾個問題
1涣澡、EventBus是如何確定哪些方法是訂閱方法的
答:通過源碼分析知道贱呐,EventBus注冊是傳入一個類對象,然后對類對象的所有方法(包括其父類的所有方法)進(jìn)行遍歷入桂,然后根據(jù)一定的規(guī)則過濾訂閱方法奄薇,分析過程中已列出,可以重新查看SubscriberMethodFinder類中的findUsingReflectionInSingleClass()方法抗愁;
2惕艳、EventBus是如何做線程切換的
答:通過Handler由子線程切換到主線程;通過實(shí)現(xiàn)Runable接口驹愚,切換至子線程處理,線程切換后通過反射調(diào)用訂閱方法分發(fā)事件
3劣纲、EventBus為什么不支持跨進(jìn)程
答:咋一看我們好像沒有再源碼中分析這一問題逢捺,其實(shí)這是一個需要理解的問題;首先我們需要理解Android的沙箱隔離機(jī)制癞季,Android中為了各應(yīng)用的安全劫瞳,不允許應(yīng)用直接訪問其他應(yīng)用倘潜,所以Android中應(yīng)用通訊就需要另一個技術(shù)實(shí)現(xiàn)--IPC跨進(jìn)程通訊,我們回想下EventBus注冊時保存的訂閱方法的map集合志于,是保存在內(nèi)存中的涮因,我們Post發(fā)送事件時也是直接在內(nèi)存中取出map中的方法,整個過程數(shù)據(jù)都涉及任何的IPC通訊伺绽。所以自然無法做到跨進(jìn)程調(diào)用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末养泡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子奈应,更是在濱河造成了極大的恐慌澜掩,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杖挣,死亡現(xiàn)場離奇詭異肩榕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)惩妇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門株汉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人歌殃,你說我怎么就攤上這事乔妈。” “怎么了挺份?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵褒翰,是天一觀的道長。 經(jīng)常有香客問我匀泊,道長优训,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任各聘,我火速辦了婚禮揣非,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘躲因。我一直安慰自己早敬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般价认。 火紅的嫁衣襯著肌膚如雪儒喊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機(jī)與錄音使鹅,去河邊找鬼篇亭。 笑死绝淡,一個胖子當(dāng)著我的面吹牛宙刘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牢酵,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼悬包,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了馍乙?” 一聲冷哼從身側(cè)響起布近,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎潘拨,沒想到半個月后吊输,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡季蚂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年琅束,在試婚紗的時候發(fā)現(xiàn)自己被綠了涩禀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡葵腹,死狀恐怖践宴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情爷怀,我是刑警寧澤阻肩,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站运授,受9級特大地震影響烤惊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吁朦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一柒室、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逗宜,春花似錦雄右、人聲如沸剥啤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至刻诊,卻和暖如春防楷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背则涯。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工复局, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粟判。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓亿昏,卻偏偏與公主長得像角钩,于是被迫代替她去往敵國和親递礼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361