EventBus中HandlerPoster,BackgroundPoster,AsyncPoster的执行流程

前言

EventBus中有几种线程模式,这几种线程模式分别代表注册的方法可以运行在主线程,或者子线程,其中这几种线程模式之间的线程切换都是用HandlerPoster,BackgroundPoster,AsyncPoster实现的,这里就来分析下它们的具体实现,看下别人的设计思想。


EventBus的ThreadMode

ThreadMode是一个枚举类,每个实例都是一种线程状态,具体看下表的每个线程ThreadMode作用

ThreadModemean
POSTING在那个线程post就在线程执行method
MAIN在主线程执行method,可能会阻塞主线程
MAIN_ORDERED在主线程执行method,每次都将事件发送到队列,然后由handle发送执行
BACKGROUND在后台线程中执行,一个线程执行完之后才会去执行另外一个线程
ASYNC在后台线程中执行,每来一个线程执行一个,事件是并发的

postToSubscription

在调用post发送事件之后,都会走到postToSubscription方法中,在这个方法中会根据threadMode去区分该在什么情况下调用事件方法

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        //POSTING 直接去调用事件
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        //MAIN 先判断是否在主线程,在,就会直接调用,不过一般不建议在事件方法中执行过多的逻辑操作,否则会阻塞主线程
        //否则通过mainThreadPoster.enqueue将事件发送给主线程执行方法,里面会有一个队列排队的过程,不会阻塞主线程
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        //mainThreadPoster默认不过null, 所以这种情况下会直接将事件发送给一个队列,然后依次取出,发送给主线程执行,这种情况下不会阻塞主线程    
        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;
        ...
    }
}

具体解释上面的注释已经解释清楚了,下面来看HandlerPoster,BackgroundPoster,AsyncPosterEventBus中的使用。


HandlerPoster

它继承Handler实现Poster,可以看出内部是通过Handler将事件从子线程发送给主线程,当在子线程中时候,会通过调用enqueue发送事件,看下其实现

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

在这段代码中首先通过PendingPost.obtainPendingPost(subscription, event)获取一个PendingPost,看下obtainPendingPost的实现

   static PendingPost obtainPendingPost(Subscription subscription, Object event) {
       synchronized (pendingPostPool) {
           int size = pendingPostPool.size();
           if (size > 0) {
               PendingPost pendingPost = pendingPostPool.remove(size - 1);
               pendingPost.event = event;
               pendingPost.subscription = subscription;
               pendingPost.next = null;
               return pendingPost;
           }
       }
       return new PendingPost(event, subscription);
   }

它首先会去检测pendingPostPool中是否有数据,如果有,直接remove,获取一个PendingPost, 并将subscriptionevent赋值给pendingPost的参数,如果pendingPostPool中没有数据,直接去new一个PendingPost

回到HandlerPosterenqueue方法,当获取到pendingPost之后,会调用queue.enqueue(pendingPost),来看下enqueue的实现

synchronized void enqueue(PendingPost pendingPost) {
        if (pendingPost == null) {
            throw new NullPointerException("null cannot be enqueued");
        }
        //链表数据接口,头部为head,下一次再进来tail.next指向pendingPost,tail向下移
        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();
    }

它的内部其实就是一个链表的数据结构,当第一次执行的时候, 直接将pendingPost赋值给tailhead,下次再进来的时候,将值赋值给tailnext,然后让tail指向新的值,这就是一个典型的链表数据结构。

回到HandlerPosterenqueue方法,接下来会去调用sendMessage,然后就会去回调handleMessage, 在这个中去执行消息

public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                //从队列中获取pendingPost
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        // 再次获取pendingPost,如果没有了,就没有消息了
                        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;
        }
    }

它会从队列中获取一个pendingPost,然后调用eventBus.invokeSubscriber去执行事件方法,看下invokeSubscriber的具体实现

 void invokeSubscriber(PendingPost pendingPost) {
     Object event = pendingPost.event;
     Subscription subscription = pendingPost.subscription;
     //释放占用的资源
     PendingPost.releasePendingPost(pendingPost);
     if (subscription.active) {
         invokeSubscriber(subscription, event);
     }
 }

最终会调用invokeSubscriber(subscription, event)去执行事件方法,同时之前会调用releasePendingPost释放pengingpost资源资源。到此这个HandlerPoster发送事件到事件执行完流程也就分析完了。


BackgroundPoster

它实现了RunnablePoster两个接口,同时发送事件也是调用的enqueue,看下其实现

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

也是将事件通过PendingPost存到一个链表队列中,然后调用eventBus.getExecutorService().execute(this)线程池执行这个异步任务,同时里面也有个executorRunning变量来保证事件是顺序执行的。

EventBus的默认线程池是Executors.newCachedThreadPool(),当然也可以通过EventbusBuilder传入我们自定义的线程池

看下run方法的实现

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) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

run方法里面也是通过循环取出队列中的任务执行,然后调用eventBus.invokeSubscriber(pendingPost)去执行异步任务。


AsyncPoster

它也是实现RunnablePoster两个接口,同时也是通过enqueue发送事件,看下实现

public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        eventBus.getExecutorService().execute(this);
    }

BackgroundPoster不同的是里面没有同步代码块,每次来一个任务都会调用执行,也就是说没执行一个任务都会开一个子线程

看下run方法的实现

@Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

里面是每次调用run方法,只会执行一次queue.poll(),然后调用eventBus.invokeSubscriber(pendingPost)执行异步任务。

到此三个Poster也就分析完了


总结

1.HandlerPoster,BackgroundPoster,AsyncPoster三个Poster都是实现了Poster接口,发送事件通过enqueue发送
2.发送的事件是封装到PendingPost中了,然后存到一个消息队列中
3.BackgroundPoster里面封装的是一个Handler,通过sendMessage将事件从子线程发送给主线程
4.BackgroundPoster里面是通过eventBus.getExecutorService().execute执行异步任务,和AsyncPoster不同的是,它执行完异步任务之后,才会去执行下一个任务。
5.AsyncPoster里面是通过eventBus.getExecutorService().execute执行异步任务,和BackgroundPoster不同的是,它每次发送一次事件,都会开一个子线程去执行异步任务。

看了EventBus的源码,其实难度不大,但是里面的设计思想还是很值得学习的,复习到了很多东西,注解,线程池,handler,反射,注解处理器等等,以后还是需要多读像这样比较经典的第三方库的源码的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值