欢迎转载,转载请注明出处:https://blog.csdn.net/FreddyChen/article/details/89530320
写在前面
由于上一篇文章《开源一个自用的Android IM库,基于Netty+TCP+Protobuf实现。》得到了不错的反响,激发了写作的兴趣,趁着时间空闲,决定继续写一些文章,以下这篇,是一个自定义的Android事件分发中心库,实现类似系统广播、EventBus、RxBus的事件发布-订阅功能,后续有时间,会继续完善之前的NettyChat库,包括加入WebSocket协议实现、UDP协议实现以及大家需要的UI页面的封装(包含会话列表页、消息列表页等),敬请期待。
本文的CEventCenter基于对象池及接口回调实现,主要解决在Activity/Fragment/Service之间的消息事件传递问题,由于作者水平有限,文中有不对之处欢迎批评与指正。
老规矩,先来看看效果:
可以看到,在B Activity发布事件后,A Activity中的TextView文本改变了。
不想看文章的同学可以直接移步到Github fork源码:github地址
接下来,让我们进入正题。
为什么不用BroadcastReceiver?
首先,BroadcastReceiver是重量级的、消耗资源较多的方式。其次,我们都知道,onReceive()方法是在主线程运行的,执行时间不能超过10秒,否则会导致ANR。那么,大家可能会有疑惑,直接在onReceive()中开启一个子线程处理耗时任务不就可以了吗?这种方式,不能说不行,只能说并不可靠。Receiver只在onReceive方法执行时是激活状态,只要onReceive一返回,Receiver就不再是激活状态了。由于activity可能会被用户退出,Broadcast Receiver的生命周期本身就很短,可能出现的情况是:
在子线程还没有结束的情况下,Activity已经被用户退出了,或者BroadcastReceiver已经结束了。在Activity已经退出、BroadcastReceiver已经结束的情况下,此时它们所在的进程就变成了空进程(没有任何活动组件的进程),系统需要内存时可能会优先终止该进程。如果宿主进程被终止,那么该进程内的所有子线程也会被中止,这样就可能导致子线程无法执行完成。
以上摘自:为什么不能在BroadcastReceiver中开启子线程
为什么不用RxBus?
其实我也有在用,记得在17年初的时候,我们当时在做一个直播项目,其中的消息事件传递,就是用的RxBus,当时是这样的:观众给主播送礼,是通过im给服务端发送消息,服务端收到送礼消息后,处理送礼的逻辑,然后给客户端返回送礼的状态消息,客户端收到消息后,通过RxBus把消息传递到Activity(其实这里不管是通过im还是http接口请求,都存在相同的问题)。在压测的时候,是每个50ms送一个礼物,很大的概率会出现一个bug,就是下图这个:
出现这个bug,是因为我们当时用的RxBus版本,内部是使用的RxJava1.0,而RxJava1.0是有一个设计缺陷的,也就是不支持背压,简单地说,抛出MissingBackpressureException往往就是因为,被观察者发送事件的速度太快,而观察者处理太慢,而且你还没有做相应措施,所以报异常。
当时心态炸了啊,因为项目比较庞大,撇弃RxBus的话,那工作量将非常巨大,而且当时项目着急上线,无奈之下,只能把可能出现这个bug的所有地方,替换成自己实现的CEventCenter,后续再逐步逐步替换…当然了,目前的RxJava已经修复了背压的问题,而CEventCenter在那之后也一直在使用,目前来说暂时没发现有什么问题,所以也就保持在用了,大家如果采用此库,在使用过程中如果发现问题,烦请联系我,我个人也是不提倡重复造轮子的,如果目前有比较好用的库,那就没必要重新开发一个,当然,如果时间允许,自己写一个其实也不错,至少在这过程中,一定会有所收获。
为什么不用EventBus?
目前EventBus最新的版本应该是3.x,这里面就有一个比较坑爹的设计:事件只能通过事件的类名来区分。
这至少带来了3大问题:
- 操作麻烦,每一个事件,都要定义一个类;
- 增加方法数;
- 导致事件发送者和接收者都依赖耦合事件类。
以上摘自:EventBus的缺点及改进升级,原作者也提供了改进的思路,有兴趣可以进去看看,当然了,EventBus的线程模型设计和粘性事件的支持是非常好的。
什么是对象池?为什么要使用对象池?
上面有提到,CEventCenter是基于对象池及接口回调实现的,那么,什么是对象池?其实大家应该都使用过OkHttp,了解过源码的应该都知道,OkHttp源码里面,就有一种叫做连接池的东西,而对象池,跟连接池类似。
在java中,对象的生命周期包括对象创建、对象使用,对象消失三个时间段,其中对象的使用是对象真正需要存活的时间,不好修改,该用的时候还得使用啊。对象的创建和消失就得好好控制下了。对象的创建是比较费时间的,也许感觉不到,好比一个赋值操作int i=1,也是需要耗时的,在比如构造一个对象,一个数组就更加消耗时间。再说对象的消除,在 java 里面使用G