Eventbus基礎(chǔ)功能源碼解析

BroadcastReceiver

? 本質(zhì)上是一個(gè)監(jiān)聽器捆交,分為接收者和發(fā)送者淑翼。用于監(jiān)聽(接收)應(yīng)用發(fā)出的廣播消息,并做出響應(yīng)品追⌒ǎ可用于進(jìn)程間通信、線程間通信和監(jiān)聽系統(tǒng)的特定時(shí)間(如:電話呼入肉瓦,網(wǎng)絡(luò)狀態(tài)變更等)遭京。

  • 使用觀察者模式:基于消息的發(fā)布/訂閱事件模型。

  • 常用做與android 系統(tǒng)事件的監(jiān)聽和交互泞莉。

  • 消耗時(shí)間哪雕、空間較多,在onRecieve()方法內(nèi)可以獲得Context和Intent參數(shù)鲫趁,通過這兩個(gè)方法斯嚎,可以調(diào)用AndroidSDK中的很多方法,屬于重量級組件挨厚。

  • 可跨進(jìn)程通信堡僻。

Eventbus

? 針對android跨進(jìn)程、線程通信的優(yōu)化方案疫剃,一定程度上可以代替廣播钉疫、handler、Intent慌申。

優(yōu)點(diǎn)

  • 調(diào)度靈活陌选,不依賴于context理郑。
  • 可繼承。
  • 有事件優(yōu)先級咨油。
  • 粘性事件機(jī)制您炉。
  • 量級較輕。

1. 實(shí)現(xiàn)原理

  • getDefault():通過懶漢單例模式獲取到對象

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

    在new對象時(shí)役电,使用builder模式:

    EventBus(EventBusBuilder builder) {
            subscriptionsByEventType = new HashMap<>();
            typesBySubscriber = new HashMap<>();
            stickyEvents = new ConcurrentHashMap<>();
            mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
            backgroundPoster = new BackgroundPoster(this);
            asyncPoster = new AsyncPoster(this);
            indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
            subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                    builder.strictMethodVerification, builder.ignoreGeneratedIndex);
            logSubscriberExceptions = builder.logSubscriberExceptions;
            logNoSubscriberMessages = builder.logNoSubscriberMessages;
            sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
            sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
            throwSubscriberException = builder.throwSubscriberException;
            eventInheritance = builder.eventInheritance;
            executorService = builder.executorService;
        }
    
  • register()實(shí)現(xiàn)如下:

    public void register(Object subscriber) {
            Class<?> subscriberClass = subscriber.getClass();
            List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//通過反射的方式獲取到所有通過注解注冊的回調(diào)方法
            synchronized (this) {
                for (SubscriberMethod subscriberMethod : subscriberMethods) {
                    subscribe(subscriber, subscriberMethod);//這里是具體的注冊方法
                }
            }
        }
    

    Subscribe():

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
            Class<?> eventType = subscriberMethod.eventType;//獲取觸發(fā)本次消費(fèi)的事件類型
            Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//創(chuàng)建訂閱對象(把注冊者和事件消費(fèi)方法綁定)
            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            } else {
                if (subscriptions.contains(newSubscription)) {//若該事件(注冊者和消費(fèi)方法)已注冊赚爵,則拋異常
                    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) {//輪詢的目的是為了按照優(yōu)先級插入到指定的位置(事件消費(fèi)隊(duì)列)
                    subscriptions.add(i, newSubscription);
                    break;
                }
            }
    
            List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//獲取該訂閱者下的所有訂閱事件
            if (subscribedEvents == null) {
                subscribedEvents = new ArrayList<>();
                typesBySubscriber.put(subscriber, subscribedEvents);
            }
            subscribedEvents.add(eventType);//將本事件添加進(jìn)觸發(fā)事件列表中
    
            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);
                }
            }
        }
    

    以上就是EventBus注冊時(shí)的邏輯,接下來我們看看發(fā)布事件的時(shí)候的邏輯:

  • post():

    public void post(Object event) {
            PostingThreadState postingState = currentPostingThreadState.get();
            List<Object> eventQueue = postingState.eventQueue;//獲取當(dāng)前線程的消息隊(duì)列
            eventQueue.add(event);//將本事件添加進(jìn)消息隊(duì)列中
    
            if (!postingState.isPosting) {//若當(dāng)前
                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()) {//循環(huán)遍歷事件隊(duì)列(在這兒可以類比handler機(jī)制不過不是死循環(huán)法瑟,也不存在阻塞冀膝,每post一次就進(jìn)行判斷,是否處于posting)
                        postSingleEvent(eventQueue.remove(0), postingState);//主要的消費(fèi)邏輯
                    }
                } finally {
                    postingState.isPosting = false;
                    postingState.isMainThread = false;
                }
            }
        }
    

    這個(gè)currentPostingThreadState是做什么的呢霎挟,我們可以看一下它的聲明和實(shí)現(xiàn):

        private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
            @Override
            protected PostingThreadState initialValue() {
                return new PostingThreadState();
            }
        };
    
    

    這里使用了ThreadLocal窝剖,說明在每個(gè)線程里都會(huì)有這個(gè)對象的副本。我們接著往下看PostingThreadState是維護(hù)什么的類:

    final static class PostingThreadState {
            final List<Object> eventQueue = new ArrayList<Object>();//事件隊(duì)列酥夭,用一個(gè)list維護(hù)
            boolean isPosting;//是否在發(fā)布事件(就是之后的循環(huán)遍歷是否在執(zhí)行)
            boolean isMainThread;//是否為主線程赐纱,通過判斷當(dāng)前l(fā)ooper是否為MainLooper
            Subscription subscription;//當(dāng)前的訂閱類,上面有說明
            Object event;//當(dāng)前正在處理的事件
            boolean canceled;//當(dāng)前事件是否被取消
        }
    

    我們繼續(xù)看postSingleEvent()方法熬北,這里是事件消費(fèi)的主要邏輯:

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

    這里可以看到最終都會(huì)回調(diào)postSingleEventForEventType()這個(gè)方法疙描,我們繼續(xù)看這個(gè)方法:

    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;//當(dāng)前正在處理的事件
                    postingState.subscription = subscription;//當(dāng)前正在輪詢的訂閱事件
                    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;
        }
    

    我們接著看:

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
            switch (subscription.subscriberMethod.threadMode) {//這里就是處理線程模式的不同策略
                case POSTING:
                    invokeSubscriber(subscription, event);
                    break;
                case MAIN:
                    if (isMainThread) {
                        invokeSubscriber(subscription, event);
                    } else {
                        mainThreadPoster.enqueue(subscription, event);
                    }
                    break;
                case BACKGROUND:
                    if (isMainThread) {
                        backgroundPoster.enqueue(subscription, event);
                    } else {
                        invokeSubscriber(subscription, event);
                    }
                    break;
                case ASYNC:
                    asyncPoster.enqueue(subscription, event);
                    break;
                default:
                    throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
            }
        }
    

    我們從默認(rèn)的POSTING模式往下看:

        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);//最終是通過反射的方法調(diào)用事件的處理
            } catch (InvocationTargetException e) {
                handleSubscriberException(subscription, event, e.getCause());
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Unexpected exception", e);
            }
        }
    

    這樣我們可以知道,最后調(diào)用方法是通過反射來調(diào)用與之對應(yīng)的消費(fèi)事件的方法讶隐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末起胰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子巫延,更是在濱河造成了極大的恐慌效五,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烈评,死亡現(xiàn)場離奇詭異火俄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)讲冠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門瓜客,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人竿开,你說我怎么就攤上這事谱仪。” “怎么了否彩?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵疯攒,是天一觀的道長。 經(jīng)常有香客問我列荔,道長敬尺,這世上最難降的妖魔是什么枚尼? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮砂吞,結(jié)果婚禮上署恍,老公的妹妹穿的比我還像新娘。我一直安慰自己蜻直,他們只是感情好盯质,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著概而,像睡著了一般呼巷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赎瑰,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天王悍,我揣著相機(jī)與錄音,去河邊找鬼乡范。 笑死配名,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晋辆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼宇整,長吁一口氣:“原來是場噩夢啊……” “哼瓶佳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鳞青,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤霸饲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后臂拓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厚脉,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年胶惰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了傻工。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孵滞,死狀恐怖中捆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坊饶,我是刑警寧澤泄伪,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站匿级,受9級特大地震影響蟋滴,放射性物質(zhì)發(fā)生泄漏染厅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一津函、第九天 我趴在偏房一處隱蔽的房頂上張望糟秘。 院中可真熱鬧,春花似錦球散、人聲如沸尿赚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屋讶。三九已至冰寻,卻和暖如春斩芭,著一層夾襖步出監(jiān)牢的瞬間乐疆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工琴庵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仰美,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓庆寺,卻偏偏與公主長得像诉字,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子奏窑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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

  • EventBus基本使用 EventBus基于觀察者模式的Android事件分發(fā)總線撩匕。 從這個(gè)圖可以看出墨叛,Even...
    顧氏名清明閱讀 616評論 0 1
  • 項(xiàng)目到了一定階段會(huì)出現(xiàn)一種甜蜜的負(fù)擔(dān):業(yè)務(wù)的不斷發(fā)展與人員的流動(dòng)性越來越大模蜡,代碼維護(hù)與測試回歸流程越來越繁瑣忍疾。這個(gè)...
    fdacc6a1e764閱讀 3,163評論 0 6
  • EventBus源碼理解 EventBus是我們在開發(fā)中經(jīng)常使用的開源庫卤妒,使用起來比較簡單,而且源碼看起來不是很吃...
    崔老板閱讀 247評論 0 2
  • 先吐槽一下博客園的MarkDown編輯器则披,推出的時(shí)候還很高興博客園支持MarkDown了洗出,試用了下發(fā)現(xiàn)支持不完善就...
    Ten_Minutes閱讀 557評論 0 2
  • EventBus用法及解析 EventBus介紹: EventBus主要是用來組件之間進(jìn)行信息傳遞的翩活,相對于接口回...
    111_222閱讀 542評論 0 1