Eventbus基礎功能源碼解析

BroadcastReceiver

? 本質上是一個監聽器,分為接收者和發送者。用于監聽(接收)應用發出的廣播消息,并做出響應。可用于進程間通信、線程間通信和監聽系統的特定時間(如:電話呼入,網絡狀態變更等)。

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

  • 常用做與android 系統事件的監聽和交互。

  • 消耗時間、空間較多,在onRecieve()方法內可以獲得Context和Intent參數,通過這兩個方法,可以調用AndroidSDK中的很多方法,屬于重量級組件。

  • 可跨進程通信。

Eventbus

? 針對android跨進程、線程通信的優化方案,一定程度上可以代替廣播、handler、Intent。

優點

  • 調度靈活,不依賴于context。
  • 可繼承。
  • 有事件優先級。
  • 粘性事件機制。
  • 量級較輕。

1. 實現原理

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

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

    在new對象時,使用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()實現如下:

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

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

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

  • post():

    public void post(Object event) {
            PostingThreadState postingState = currentPostingThreadState.get();
            List<Object> eventQueue = postingState.eventQueue;//獲取當前線程的消息隊列
            eventQueue.add(event);//將本事件添加進消息隊列中
    
            if (!postingState.isPosting) {//若當前
                postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                postingState.isPosting = true;
                if (postingState.canceled) {
                    throw new EventBusException("Internal error. Abort state was not reset");
                }
                try {
                    while (!eventQueue.isEmpty()) {//循環遍歷事件隊列(在這兒可以類比handler機制不過不是死循環,也不存在阻塞,每post一次就進行判斷,是否處于posting)
                        postSingleEvent(eventQueue.remove(0), postingState);//主要的消費邏輯
                    }
                } finally {
                    postingState.isPosting = false;
                    postingState.isMainThread = false;
                }
            }
        }
    

    這個currentPostingThreadState是做什么的呢,我們可以看一下它的聲明和實現:

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

    這里使用了ThreadLocal,說明在每個線程里都會有這個對象的副本。我們接著往下看PostingThreadState是維護什么的類:

    final static class PostingThreadState {
            final List<Object> eventQueue = new ArrayList<Object>();//事件隊列,用一個list維護
            boolean isPosting;//是否在發布事件(就是之后的循環遍歷是否在執行)
            boolean isMainThread;//是否為主線程,通過判斷當前looper是否為MainLooper
            Subscription subscription;//當前的訂閱類,上面有說明
            Object event;//當前正在處理的事件
            boolean canceled;//當前事件是否被取消
        }
    

    我們繼續看postSingleEvent()方法,這里是事件消費的主要邏輯:

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
            Class<?> eventClass = event.getClass();
            boolean subscriptionFound = false;
            if (eventInheritance) {
                List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
                int countTypes = eventTypes.size();
                for (int h = 0; h < countTypes; h++) {
                    Class<?> clazz = eventTypes.get(h);
                    subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
                }
            } else {
                subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
            }
            if (!subscriptionFound) {
                if (logNoSubscriberMessages) {
                    Log.d(TAG, "No subscribers registered for event " + eventClass);
                }
                if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                        eventClass != SubscriberExceptionEvent.class) {
                    post(new NoSubscriberEvent(this, event));
                }
            }
        }
    

    這里可以看到最終都會回調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;
        }
    

    我們接著看:

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

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

    這樣我們可以知道,最后調用方法是通過反射來調用與之對應的消費事件的方法。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • EventBus基本使用 EventBus基于觀察者模式的Android事件分發總線。 從這個圖可以看出,Even...
    顧氏名清明閱讀 635評論 0 1
  • 項目到了一定階段會出現一種甜蜜的負擔:業務的不斷發展與人員的流動性越來越大,代碼維護與測試回歸流程越來越繁瑣。這個...
    fdacc6a1e764閱讀 3,210評論 0 6
  • EventBus源碼理解 EventBus是我們在開發中經常使用的開源庫,使用起來比較簡單,而且源碼看起來不是很吃...
    崔老板閱讀 256評論 0 2
  • 先吐槽一下博客園的MarkDown編輯器,推出的時候還很高興博客園支持MarkDown了,試用了下發現支持不完善就...
    Ten_Minutes閱讀 582評論 0 2
  • EventBus用法及解析 EventBus介紹: EventBus主要是用來組件之間進行信息傳遞的,相對于接口回...
    111_222閱讀 565評論 0 1