• EventBus源码阅读(二)——Poster


      上一节在阅读了EventBus的消息发送后,停在了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 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);
            }
        }

       在不同的模式下,当前方法在不同线程中调用,会使用不同的Poster。上次对这一点没有深究,今天来粗略的看一看。

      从上面的代码中,我们可以看到,除了直接执行方法 invokeSubscriber(subscription, event);外,还有几个特殊的Poster,分别是mainThreadPoster,backgroundPoster,和asyncPoster。

      我们来一一阅读。

      mainThreadPoster的类叫作HandlerPoster,代码不长,总共80来行。

      

    final class HandlerPoster extends Handler {
    
        private final PendingPostQueue queue;
        private final int maxMillisInsideHandleMessage;
        private final EventBus eventBus;
        private boolean handlerActive;
    
        HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
            super(looper);
            this.eventBus = eventBus;
            this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
            queue = new PendingPostQueue();
        }
    
        void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                queue.enqueue(pendingPost);
                if (!handlerActive) {
                    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 pendingPost = queue.poll();
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                handlerActive = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                    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。方法enqueue主要做了两件事。

      一、将事件请求放入请求队列queue中。

      二、发送一个message到MainLooper中。

      每当HandlerPoster发送message,其中的handleMessage就要开始工作。EventBus为其设置了最大工作时间。在工作时间内,程序会不断地从queue中poll出请求,在主线程中执行它,直到queue队列为空,或是到达最大工作时间,才会结束。我们可以看到,HandlerPoster其实就是对消息的发送做了处理,通过Handler,将其置于MainThread中来执行。

      BackgroundPoster:

      BackgroundPoster则是实现了Runnable接口。

    final class BackgroundPoster implements Runnable {
    
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        private volatile boolean executorRunning;
    
        BackgroundPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                queue.enqueue(pendingPost);
                if (!executorRunning) {
                    executorRunning = true;
                    eventBus.getExecutorService().execute(this);
                }
            }
        }
    
        @Override
        public void run() {
            try {
                try {
                    while (true) {
                        PendingPost pendingPost = queue.poll(1000);
                        if (pendingPost == null) {
                            synchronized (this) {
                                // Check again, this time in synchronized
                                pendingPost = queue.poll();
                                if (pendingPost == null) {
                                    executorRunning = false;
                                    return;
                                }
                            }
                        }
                        eventBus.invokeSubscriber(pendingPost);
                    }
                } catch (InterruptedException e) {
                    Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    
    }

      BackgroundPoster也维护了一个请求队列。与HandlerPoster不同的是,它不再使用message来发动任务的执行。而是eventBus.getExecutorService().execute(this);这个方法最终可以追溯到EventBusBuilder中的DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();也就是说,在BackgroundPoster中执行的任务一定不在主线程。另一个与HandlerPoster不同的点是,BackgroundPoster没有最大工作时间,但它有个最大等待时间——1000ms。如果队列为空,在等待1000ms后,队列中依然没有新的事件加入,再表示事件请求已全部执行。

    AsyncPoster:

      AsyncPoster的实现最为简单,它的功能是,不能当前处于什么线程,一定都会新开一个线程来执行这个任务。

      

    class AsyncPoster implements Runnable {
    
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        AsyncPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            queue.enqueue(pendingPost);
            eventBus.getExecutorService().execute(this);
        }
    
        @Override
        public void run() {
            PendingPost pendingPost = queue.poll();
            if(pendingPost == null) {
                throw new IllegalStateException("No pending post available");
            }
            eventBus.invokeSubscriber(pendingPost);
        }
    
    }

       代码比较简单,我们可以看出AsyncPoster是在BackgroundPoster上做的减法。去掉了线程保护(因为新开),去掉了wait(也是因为新开)。

      通过以上阅读,我们大致对EventBus的事件发送机制有了了解。下一节,我们将开始阅读,它的订阅机制。

    Done~

  • 相关阅读:
    HashSet源码分析
    Mysql的体系结构和存储引擎
    触发器
    存储过程和函数
    索引
    SpringBoot 中的日志使用
    log4j2
    Logback
    slf4j
    日志门面
  • 原文地址:https://www.cnblogs.com/fishbone-lsy/p/5410699.html
Copyright © 2020-2023  润新知