本篇博文理论知识储备:
Otto源码解读
EventBus源码解析开篇
EventBus BackgroundPoster原理解析
在阅读本篇博文之前,请先阅读上面几篇博客,可以对EventBus的工作原理做一个系统的了解。
EventBus的在EventBus BackgroundPoster原理解析一文中详细的说明了ThreadModel.BACKGROUND 的工作原理、PendingPostQueue事件链表的构建以及PendingPost对象的复用技术。本篇博文继续分析EventBus的一些其他的知识点。

通过上面的几篇博文可以总结出EventBus的核心工作原理:其中PendingPostQueue是整个EventBus的核心,它构成了EventBus的事件链表结构,而从链表中获取事件对象PendingPost的不同方式,在EventBus中表现为不同的ThreadModel,比如而ThreadModel.BACKGROUND则是在非UI线程中操作PendingPostQueue链表,来操控事件从发布到执行都是在非UI线程中执行;HandlerPoster对应的就是ThreadModel.MAIN,表明是在UI线程中获取PendingPostQueue链表中的元素(PendingPost对象)进行处理。这从某种程度上来看,有点类似于策略模式。

在EventBus种Poster接口的不同实现,就是对应着不同的ThreadModel。本文就对另外一个Poster----HandlerPoster做一个简单的分析。在android种一切于UI线程操作有关的东西都少不了Handler的影子(详见android消息处理机制原理解析),在EventBus中处理ThreadModel.MAIN的相关代码如下:

 case MAIN:if (isMainThread) {//1、如果已经处于UI线程,则直接调用invokeSubscriber(subscription, event);} else {//2、如果非UI线程,则调用mainThreadPoster处理mainThreadPoster.enqueue(subscription, event);}break;

在MAIN这个case分支中对于是否处于UI作了判断,如果事件的产生本身处于UI线程则直接调用invokeSubscriber让subscription这个对象处理事件(subscription类似于Otto的EventHandler对象),注意EventBus的invokeSubscriber方法就是最终消费事件的方法。当处于非UI线成的时候就调用mainThreadPoster.enqueue的来让事件的消费切换到UI线程中执行。

在这里mainThreadPoster如果客户端不做额外配置的话就是EventBus内置的HandlerPoster了:

//本身是一个Handler,也是一个Post接口的实现类
public class HandlerPoster extends Handler implements Poster {private final PendingPostQueue queue;private final int maxMillisInsideHandleMessage;private final EventBus eventBus;private boolean handlerActive;
}

进入Poster接口的enqueue方法来看看其具体的实现:

 public void enqueue(Subscription subscription, Object event) {//将subscription和event构建成一个PendingPost对象PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);synchronized (this) {//将pendingPost插入到事件链表的尾部queue.enqueue(pendingPost);if (!handlerActive) {handlerActive = true;//发送消息,执行handleMessageif (!sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message");}}}}

整体来说就是先讲事件处理对象subscription和事件event封装成一个PendingPost,继而将pendingPost对象插入的PendingPost链表中(详见EventBus BackgroundPoster原理解析),然那调用sendMessage交给Handler的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 synchronizedpendingPost = queue.poll();if (pendingPost == null) {handlerActive = false;return;}}}//进行事件处理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;}}
}

可以看出handleMessage对事件链表的处理是不断循环获取链表中的PendingPost,当链表中的事件处理完毕后退出while循环。或者是在规定的时间内maxMillisInsideHandleMessage没有将事件处理完,则继续调用sendMessage。继而重新回调handleMessage方法,事件会继续执行。这是为了避免队列过长或者事件耗时较长时,while循环阻塞主线程造成卡顿。算是个小技巧。


到此为止HandlerPoster算是讲解完毕,作为一个公共库除了对内提供默认支持以外,对外提供良好的扩展性也是很有必要的,方便用户用自己的实现来替代库中的默认实现(构建者模式在此中情况下使用最合理)。

在EventBus 中除了用HandlerPoster默认实现将事件切换到主线程执行之外,EventBus还提供了MainThreadSupport这个接口:

public interface MainThreadSupport {boolean isMainThread();//返回客户端自定义的ThreadModel.MAIN处理方式Poster createPoster(EventBus eventBus);}//EventBus中的默认实现class AndroidHandlerMainThreadSupport implements MainThreadSupport {private final Looper looper;public AndroidHandlerMainThreadSupport(Looper looper) {this.looper = looper;}@Overridepublic boolean isMainThread() {return looper == Looper.myLooper();}@Overridepublic Poster createPoster(EventBus eventBus) {//默认使用HandlerPoster对象return new HandlerPoster(eventBus, looper, 10);}}

mainThreadPoster接口提供了一个createPoster方法,由客户端自己初始化ThreadModel.Main的处理方式,在EventBus类中初始化mainThreadPoster代码如下:

    private final MainThreadSupport mainThreadSupport;private final Poster mainThreadPoster;EventBus(EventBusBuilder builder) {mainThreadSupport = builder.getMainThreadSupport();//默认返回的就是HandlerPoster对象mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;}

可以看出就是一个构建者模式的应用,如果客户端没有实现自己的MainThreadSupport接口则默认使用HandlerPoster.其实就一个构建者模式的使用;其实第三方库中构建者模式是常用的设计模式之一,此处可以再次体会到该模式的便利之处。

本篇博文到此结束,如有不当之处欢迎批评指正。

EventBus HandlerPoster简单分析相关推荐

  1. R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集、非线性:基函数展开和样条分析、你简单分析的不重要特征,可能只是线性不显著、而非线性是显著的

    R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集.非线性:基函数展开和样条分析.你简单分析的不重要特征,可能只是线性不显著.而非线性是显著的 目录

  2. [EntLib]微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇...

    在完成了后,今天开始介绍企业库中的新模块:Cryptographer(加密模块),这个模块在日常的大多数项目的作用非常重要,例如:网站会员密码.身份证号.网站配置等,通过对信息进行加密可以保证项目数据 ...

  3. android EventBus的简单使用

    今天,简单讲讲Android里关于EventBus的使用. 这几天,由于面试的缘故,我听到了很多Android的流行框架,但是之前自己在公司做APP时并没有使用,所以没有了解.于是在网上查找了资料,学 ...

  4. android EventBus的简单使用

    今天,简单讲讲Android里关于EventBus的使用. 这几天,由于面试的缘故,我听到了很多Android的流行框架,但是之前自己在公司做APP时并没有使用,所以没有了解.于是在网上查找了资料,学 ...

  5. FFmpeg资料来源简单分析:libswscale的sws_getContext()

    ===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...

  6. howdoi 简单分析

    对howdoi的一个简单分析. 曾经看到过下面的这样一段js代码: try{doSth(); } catch (e){ask_url = "https://stackoverflow.com ...

  7. Mac与Phy组成原理的简单分析

    Mac与Phy组成原理的简单分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fir ...

  8. python做数据可视化的代码_Python数据可视化正态分布简单分析及实现代码

    Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候... 正态分布(Normaldistribution),也称"常态分布",又名高斯分布(Gaussiandi ...

  9. ASIHTTPRequest源码简单分析

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 ASIHttprequest 是基于CFNetwork的,由于CFNetwork是比较底层的http库,功能比较少, ...

  10. Hessian 源码简单分析

    Hessian 源码简单分析 Hessian 是一个rpc框架, 我们需要先写一个服务端, 然后在客户端远程的调用它即可. 服务端: 服务端通常和spring 做集成. 首先写一个接口: public ...

最新文章

  1. django -- url 的 name 属性
  2. failed to get the task for process XXX(解决方案)
  3. 这10个好习惯助你成为优秀的程序员
  4. 数据结构与算法--二叉查找树实现原理
  5. 前端学习(741):通过榨汁机看透函数
  6. python class def 格式_Python symbol.classdef方法代码示例
  7. 使用EL表达式,显示Action中的数据
  8. 回顾2016,工作总结!
  9. Bailian2884 Problem III【入门】
  10. sap gui java_不喜欢SAP GUI?那试试用Eclipse进行ABAP开发吧
  11. 【Matlab学习笔记】【图像滤波去噪】以-4,-8为中心的拉普拉斯滤波器
  12. MFC中.和-的区别
  13. 通达OA - 数据备份与恢复指南
  14. 分布式一致性—Paxos算法
  15. 通过QQ 2012 客户端协议获取clientkey的0x91数据包分析
  16. 学习大数据最正确的步骤(0基础必备)
  17. dingo php,Laravel Dingo API
  18. 几种能让Mac“飞”起来的系统空间清理方法
  19. 一款科幻题材基地建设策略游戏——太空避难所中文版 附游戏玩法
  20. OFDM时频脉冲形状与子载波正交性的理解

热门文章

  1. 怎么在电脑上看磁盘分配单元的大小_不升级配件、4种方法让电脑提速50%!
  2. 因为此网站使用了 hsts_HSTS原理及实践
  3. Vue:结合ElementUI元素超过一定高度加滚动框,高度由浏览器高度决定并随浏览器变化而变化
  4. 实战JavaScript:实现贪吃蛇——面向对象练习
  5. 爬虫:Python爬虫学习笔记之爬虫基础
  6. 可变车道怎么走不违章_可变车道怕走错扣分罚款,学学老司机的办法,新手司机学会不吃亏...
  7. SLAM:无人系统和增强现实overview
  8. KL距离-Kullback-Leibler Divergence
  9. YOLOv4中的数据增强
  10. 重磅!2020 年算法工程师技术路线图