EventBusソース分析続編

11267 ワード

上記の送信方法では3つのpostイベントが使用されています.次に、これらのpostイベントを分析します.メインスレッドのスケジューリング:
  • MainThreadSupport:
  • /**
     * Interface to the "main" thread, which can be whatever you like. Typically on Android, Android's main thread is used.
     *    “ ”  ,         。   Android   Android    。
     */
    public interface MainThreadSupport {
    
        boolean isMainThread();
    
        Poster createPoster(EventBus eventBus);
    
        class AndroidHandlerMainThreadSupport implements MainThreadSupport {
    
            private final Looper looper;
    
            public AndroidHandlerMainThreadSupport(Looper looper) {
                this.looper = looper;
            }
    
            @Override
            public boolean isMainThread() {
                return looper == Looper.myLooper();
            }
    
            @Override
            public Poster createPoster(EventBus eventBus) {
                return new HandlerPoster(eventBus, looper, 10);
            }
        }
    }
    

    上記の方法から、最終的に作成されたposterはHandlerPosterであることがわかる.
  • HandlerPoster
  • public class HandlerPoster extends Handler implements Poster {
    
        private final PendingPostQueue queue; //        Post Events      
        private final int maxMillisInsideHandleMessage; // post     handlerMessage           ,            
        private final EventBus eventBus;
        private boolean handlerActive;  //    handler         
    
        protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
            super(looper);
            this.eventBus = eventBus;
            this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            //   pendingPostPool   ArrayList        PendingPost     PendingPostQueue    ,    PendingPost       Handler    
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                queue.enqueue(pendingPost); //   pendingPost       
                if (!handlerActive) {  //    Handler      
                    handlerActive = true;
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                }
            }
        }
    
        @Override
        public void handleMessage(Message msg) {
            boolean rescheduled = false;
            try {
                long started = SystemClock.uptimeMillis();
                while (true) { //    ,    PendingPost       post     
                    PendingPost pendingPost = queue.poll();
                    if (pendingPost == null) { //     null,        post   ,     Handler   ,    while   
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                handlerActive = false; //    Handler       
                                return;
                            }
                        }
                    }
                    //     post     eventBus     post       Subscriber     
                    eventBus.invokeSubscriber(pendingPost);
    
                    //         handleMessage       
                    long timeInMethod = SystemClock.uptimeMillis() - started;
                    if (timeInMethod >= maxMillisInsideHandleMessage) { //        
                        if (!sendMessage(obtainMessage())) {  //        
                            throw new EventBusException("Could not send handler message"); //     
                        }
                        rescheduled = true;
                        return;
                    }
                }
            } finally {
                handlerActive = rescheduled;
            }
        }
    }
    

    HandlerPosterは、実はHandlerの実装であり、内部でPendingPostQueueのメッセージキューを維持し、enqueue(Subscription subscription,Object event)メソッドでpendingPostPoolのArrayListキャッシュプールからPendingPostをPendingPostに追加し、そのPendingPostQueueイベントをHandlerに送信して処理する.
    handleMessageでは、1つのwhileデッドサイクルにより、PendingPostQueueからPendingPostを取り出して実行し続け、postを取得した後、eventBusがそのpostを通じて対応するSubscriber処理イベントを検索する.
  • whileが脱退する条件は2つある.取得されたPendingPostはnullであり、PendingPostQueueには処理可能なメッセージがありません.2.各PendingPostがHandlerで実行される時間が最大実行時間を超えている.
  • 2.BackgroundPoster
  • /**
     * Posts events in background.
     *        
     * @author Markus
     */
    final class BackgroundPoster implements Runnable, Poster {
    .....
        @Override
        public void run() {
            try {
                try {
                    //       PendingPostQueue    pendingPost   eventBus   
                    while (true) {
    
                        //   1000      PendingPostQueue     pendingPost
                        PendingPost pendingPost = queue.poll(1000);
    
                        //         pendingPost     null
                        if (pendingPost == null) {
                            synchronized (this) {
                                // Check again, this time in synchronized
                                pendingPost = queue.poll(); //        pendingPost
                                if (pendingPost == null) {
                                    executorRunning = false;
                                    return;
                                }
                            }
                        }
    
                        //   pendingPost    EventBus     
                        //      PendingPostQueue  【  】  pendingPost     ,      AsyncPoster
                        eventBus.invokeSubscriber(pendingPost);
                    }
                } catch (InterruptedException e) {
                    eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    }
    

    BackgroundPosterが実現したのはRunnableで、私たちはそのrun方法を見て、PendingPostQueueからpendingPostをEventBusに取り出して配布し続け、ここで外部がwhile()死循環であることに注意して、PendingPostQueueの中のすべてのpendingPostが配布されることを意味します.なぜなら、BackGroundThreadバックグラウンドスレッドは、これが唯一なので、このスレッドに送信されたイベントはキューに配置され、購読時にループしてすべて送信される必要があります.
  • 3.AsyncPosterというposterもBackgroundPosterも実装されているRunnableですが、彼らのrun方法は実装が異なり、1つの配布を取り出すだけです.理由:ASYNC:このスレッドは、パブリッシュイベントがどのスレッドにあるかにかかわらず、サブスクリプション時に空のスレッドになるため、スレッドは互いに独立してカートンは現れません.
  • class AsyncPoster implements Runnable, Poster {
        .....
    
        @Override
        public void run() {
            PendingPost pendingPost = queue.poll();
            if(pendingPost == null) {
                throw new IllegalStateException("No pending post available");
            }
    
            //   pendingPost    EventBus     
            eventBus.invokeSubscriber(pendingPost);
        }
    }
    

    3つのposterで使用されるキューPendingPostQueue:
    final class PendingPostQueue {
        private PendingPost head; //  
        private PendingPost tail; //  
    
        //   
        synchronized void enqueue(PendingPost pendingPost) {
            if (pendingPost == null) {
                throw new NullPointerException("null cannot be enqueued");
            }
            if (tail != null) { //   
                tail.next = pendingPost;
                tail = pendingPost;
            } else if (head == null) { //            
                head = tail = pendingPost;  //     ,          
            } else {
                throw new IllegalStateException("Head present, but no tail"); //     
            }
            notifyAll(); //          
        }
    
        synchronized PendingPost poll() {
            PendingPost pendingPost = head;
            if (head != null) {
                head = head.next;
                if (head == null) {
                    tail = null;
                }
            }
            return pendingPost;
        }
    
        synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
            if (head == null) {
                wait(maxMillisToWait);
            }
            return poll();
        }
    }
    
  • PendingPost:
  • final class PendingPost {
        //   ArrayList   PendingPost      
        private final static List pendingPostPool = new ArrayList();
    
        Object event;
        Subscription subscription;
        PendingPost next;
    
        private PendingPost(Object event, Subscription subscription) {
            this.event = event;
            this.subscription = subscription;
        }
    
        //    PendingPost
        static PendingPost obtainPendingPost(Subscription subscription, Object event) {
            synchronized (pendingPostPool) {
                int size = pendingPostPool.size();
                if (size > 0) {
                    PendingPost pendingPost = pendingPostPool.remove(size - 1); //     PendingPost,              
                    pendingPost.event = event;
                    pendingPost.subscription = subscription;
                    pendingPost.next = null;
                    return pendingPost;
                }
            }
            return new PendingPost(event, subscription);  // pendingPostPool             
        }
    
        //    PendingPost
        static void releasePendingPost(PendingPost pendingPost) {
            pendingPost.event = null;
            pendingPost.subscription = null;
            pendingPost.next = null;
            synchronized (pendingPostPool) {
                // Don't let the pool grow indefinitely
                if (pendingPostPool.size() < 10000) {  //              
                    pendingPostPool.add(pendingPost);
                }
            }
        }
    }
    

    5.ログアウト
    EventBus.getDefault().unregister(this);
    
  • unregisterメソッド:
  • public synchronized void unregister(Object subscriber) {
            List> 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());
            }
        }
    

    登録プロセスでは、typesBySubscriberがサブスクライバのすべてのサブスクライバイベントタイプを保存するMapであることがわかります.ここでは、サブスクライバに基づいてサブスクライバイベントタイプリストを取得し、1つずつサブスクライバをキャンセルし、最後にtypesBySubscriberがサブスクライバを削除します.
  • unsubscribeByEventTypeメソッド:
  • /**
         * Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber.
         *    subscriptionByEventType,   typesbysubscriber!       typesbysubscriber。
         */
        private void unsubscribeByEventType(Object subscriber, Class> eventType) {
            List 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--;
                    }
                }
            }
        }
    

    subscriptionsByEventTypeはイベントタイプ対応サブスクリプション情報を格納するMapであり、コードロジックが非常に明確で、あるイベントタイプのサブスクリプション情報リストを探し出し、サブスクリプション情報を遍歴し、サブスクリプションをキャンセルするサブスクライバとサブスクリプション情報をカプセル化するサブスクライバとを対比し、同一であれば、そのサブスクリプション情報が失効することを説明し、そのサブスクリプション情報を除去する.