背景

前期由于工作中需要将EventBus替换成RxBus,所以按照EventBus的用法封装了一套自己的RxBus,基本满足了使用,项目发出后有不少兄弟告诉我没有EventBus的Sticky功能,所以得闲完善这个功能,同样是按照EventBus3.0注解的方式去实现和调用

效果

这里写图片描述

sticky是什么

在Android开发中,Sticky事件只指事件消费者在事件发布之后才注册的也能接收到该事件的特殊类型。Android中就有这样的实例,也就是Sticky Broadcast,即粘性广播。正常情况下如果发送者发送了某个广播,而接收者在这个广播发送后才注册自己的Receiver,这时接收者便无法接收到刚才的广播,为此Android引入了StickyBroadcast,在广播发送结束后会保存刚刚发送的广播(Intent),这样当接收者注册完Receiver后就可以接收到刚才已经发布的广播。这就使得我们可以预先处理一些事件,让有消费者时再把这些事件投递给消费者。

使用

完全按照EventBus3.0版本的注解的方式去使用

发送消息RxBus.getDefault().post(new EventStickText("我是sticky消息"));复制代码

接收消息

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)

public void event(EventStickText eventStickText){

Observable.timer(1, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> {

textView.setText(eventStickText.getMsg());

});

}

@Override

protected void onStart(){

super.onStart();

RxBus.getDefault().register(this);

}

@Override

protected void onDestroy(){

super.onDestroy();

RxBus.getDefault().unRegister(this);

}复制代码

实现

本篇的实现原理是基于之前的RxBus封装的基础上的完善,所以需要大致了解RxBus之前基本功能的封装原理方能更加全面的理解一下的内容

1.添加sticky注解

不懂注解的同学可以先看下之前我写的两瓶关于注解的博客

这里添加boolean sticky()的方法,并且默认指定参数false

@Documented

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Subscribe {

int code() default -1;

ThreadMode threadMode() default ThreadMode.CURRENT_THREAD;

boolean sticky() default false;

}复制代码

2.将sticky加入数据封装类中

将数据新加入的注解sticky加入到数据封装类中,在最后分发事件时用于区分sticky事件

public class SubscriberMethod{

public Method method;

public ThreadMode threadMode;

public Class> eventType;

public Object subscriber;

public int code;

public boolean sticky;

public SubscriberMethod(Object subscriber, Method method, Class> eventType, int code,ThreadMode threadMode,boolean sticky ){

this.method = method;

this.threadMode = threadMode;

this.eventType = eventType;

this.subscriber = subscriber;

this.code = code;

this.sticky=sticky;

}

******

}复制代码

3.记录post事件分析

因为sticky的特殊性,而自带RxJava提供给我们四种方式处理Subject分发

ReplaySubject在订阅者订阅时,会发送所有的数据给订阅者,无论它们是何时订阅的。

PublishSubject只会给在订阅者订阅的时间点之后的数据发送给观察者。

AsyncSubject只在原Observable事件序列完成后,发送最后一个数据,后续如果还有订阅者继续订阅该Subject, 则可以直接接收到最后一个值。

BehaviorSubject在订阅者订阅时,会发送其最近发送的数据(如果此时还没有收到任何数据,它会发送一个默认值)。

所以只有ReplaySubject和BehaviorSubject具备Sticky的特性。

但是:这两种方式都不适合

BehaviorSubject因为只是保留最近一次的事件,这样会导致事件的覆盖问题

ReplaySubject能解决BehaviorSubject的事件丢失的问题,能保存所有的事件,但是分发起来确实一个难点,暂时没有找到合适的处理方法

还有我们之前的封装采用的PublishSubject的实现方式去分发RxBus的事件,如果换成任何其他的分发机制都会导致sticky事件和正常事件数据需要独立来做,成本太高

public RxBus(){

bus = new SerializedSubject<>(PublishSubject.create());

}复制代码

解决办法:通过Map手动记录消息事件,和PublishSubject数据统一起来处理,避免速度的独立,这里选择线程安全的ConcurrentHashMap

4.ConcurrentHashMap记录事件

初始化

/*stick数据*/

private final Map, Object> stickyEvent =new ConcurrentHashMap<>();复制代码

在post方法中添加事件

/**

* 提供了一个新的事件,单一类型

*

* @param o 事件数据

*/

public void post(Object o){

synchronized (stickyEvent) {

stickyEvent.put(o.getClass(), o);

}

bus.onNext(o);

}复制代码

5.通过sticky注解得到Observable对象

在register(Object subscriber)方法中通过反射得到自定义注解的数据,然后放入到自定义的数据类型SubscriberMethod中

/**

* 注册

*

* @param subscriber 订阅者

*/

public void register(Object subscriber){

/*避免重复创建*/

if(eventTypesBySubscriber.containsKey(subscriber)){

return;

}

Class> subClass = subscriber.getClass();

Method[] methods = subClass.getDeclaredMethods();

for (Method method : methods) {

if (method.isAnnotationPresent(Subscribe.class)) {

//获得参数类型

Class[] parameterType = method.getParameterTypes();

//参数不为空 且参数个数为1

if (parameterType != null && parameterType.length == 1) {

Class eventType = parameterType[0];

addEventTypeToMap(subscriber, eventType);

Subscribe sub = method.getAnnotation(Subscribe.class);

int code = sub.code();

ThreadMode threadMode = sub.threadMode();

boolean sticky = sub.sticky();

SubscriberMethod subscriberMethod = new SubscriberMethod(subscriber, method, eventType, code, threadMode,

sticky);

addSubscriberToMap(eventType, subscriberMethod);

addSubscriber(subscriberMethod);

}

}

}

}复制代码

当事件触发以后,通过SubscriberMethod记录的数据生成不同的Observable对象,现在对sticky消息增加了响应的对象处理

/**

* 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者

*/

public Observable toObservableSticky(final Class eventType){

synchronized (stickyEvent) {

Observable observable = bus.ofType(eventType);

final Object event = stickyEvent.get(eventType);

if (event != null) {

return observable.mergeWith(Observable.create(new Observable.OnSubscribe() {

@Override

public void call(Subscriber super T> subscriber){

subscriber.onNext(eventType.cast(event));

}

}));

} else {

return observable;

}

}

}复制代码

这里使用merge操作符:可以将多个Observables合并生成一个Observable。

6.Observable对象分发事件

得到sticky的压缩Observable对象后,还需要按照注解中被指定的线程去触发事件任务

/**

* 用于处理订阅事件在那个线程中执行

*

* @param observable

* @param subscriberMethod

* @return

*/

private Observable postToObservable(Observable observable, SubscriberMethod subscriberMethod){

switch (subscriberMethod.threadMode) {

case MAIN:

observable.observeOn(AndroidSchedulers.mainThread());

break;

case NEW_THREAD:

observable.observeOn(Schedulers.newThread());

break;

case CURRENT_THREAD:

observable.observeOn(Schedulers.immediate());

break;

case IO:

observable.observeOn(Schedulers.io());

break;

default:

throw new IllegalStateException("Unknown thread mode: " + subscriberMethod.threadMode);

}

return observable;

}复制代码

这里很简单,直接运用RxJava和RxAndroid的线程去管理即可

7.sticky消息的销毁

因为这里的sticky消息采用的是map队列记录的方式去实现,所以当sticky消息不在被需求记录的时候,或者程序退出,需要手动清空map队列的数据,避免内存溢出和浪费

/**

* 移除指定eventType的Sticky事件

*/

public T removeStickyEvent(Class eventType){

synchronized (stickyEvent) {

return eventType.cast(stickyEvent.remove(eventType));

}

}

/**

* 移除所有的Sticky事件

*/

public void removeAllStickyEvents(){

synchronized (stickyEvent) {

stickyEvent.clear();

}

}复制代码

结果

通过sticky消息的完善,RxBus已经完全实现了EventBus3.0的全部功能,并且全部安装EventBus3.0的使用方法来封装,方便项目的迁移和使用。

注解方式定义

post方式分发事件

sticky消息功能

注册销毁简单化

源码

建议

android rxbus github,RxBus-实现EventBus之Sticky相关推荐

  1. 清纯不做作的RxBus,用法与EventBus 一致

    清纯不做作的RxBus ,用法与EventBus 一致 前言 看过一些别人写的Rxbus , @Subscribe( thread = EventThread.IO, tags = { @Tag(Bu ...

  2. Android 框架学习1:EventBus 3.0 的特点与如何使用

    前面总结了几篇基础,在这过程中看着别人分享自定义 View.架构或者源码分析,看起来比我写的"高大上"多了,内心也有点小波动. 但是自己的水平自己清楚,基础不扎实画再多源码流程图也 ...

  3. 开源需自立!Android、GitHub、Apache全线告急!

    作者 | 胡巍巍&伍杏玲 责编 | 唐小引 出品 | CSDN(ID:CSDNnews) 华为四面楚歌,"破窗效应"爆发! 继5月16日美国商务部工业与安全局(BIS)将华 ...

  4. Android使用Github Actions持续集成并自动上传apk到蒲公英App内测分发平台(含证书密码脱敏)

    目录 1.前言 2.Github Actions持续集成 3.上传apk到蒲公英 4.Gradle配合Github Actions的Secret使用 4.1设置Github Actions Secre ...

  5. Android 源码分析之 EventBus 的源码解析

    1.EventBus 的使用 1.1 EventBus 简介 EventBus 是一款用于 Android 的事件发布-订阅总线,由 GreenRobot 开发,Gihub 地址是:EventBus. ...

  6. Android Service后台下载 广播(Eventbus)通知并展示

    因为好多项目都会用到比如后台下载apk,下载图片,音视频,这个时候就需要我们用Service进行后台下载了,首先讲一下我的思路一个简单的service后台图片下载展示,我需要创建一个service并注 ...

  7. android studio github 项目导入问题

    在github上面看到一个比较好的项目,导入出现了一些问题,记录如下: 项目演示效果如图:下载地址:https://github.com/asijack/PagerSlidingTabStrip 如果 ...

  8. Android Studio 找不到EventBus/ButterKnife等第三方包解决方案

    废话不多说,有图有真相 Q·:可以正常Build,debug就是看着不舒服,代码提示也出不来. 解决方案: 1. invalidate and restart (没用继续第二步) 2. 修改gradl ...

  9. Android studio Github 断开连接

    http://blog.csdn.net/agoodcoolman/article/details/50562301 使用软件:Android studio  svn:Github 从github直接 ...

  10. android在github上调用aar文件

    打包aar并进行远程依赖,解决引用aar时找不到aar的远程依赖库问题 AAR 打包aar并进行远程依赖,解决引用aar时找不到aar的远程依赖库问题 一.在library Module的gradle ...

最新文章

  1. 程序员看过来!JS、Java、C 依然强势,Go、Kotlin、Python 潜力股,2020 开发者生态系统报告
  2. Material Design风格登录注册
  3. opencv空间色彩转换
  4. php操作elasticsearch
  5. ORB_SLAM2+ZED 2
  6. 19. 镜像二叉树(C++版本)
  7. idea 新建的java项目没发run_IntelliJ IDEA 如何创建一个普通的java项目,及创建java文件并运行...
  8. java开发中的各种中间件技术
  9. mysql 修改字段名 sql,MySQL中使用SQL语句对字段进行重命名
  10. java 矩阵求逆_详解用java描述矩阵求逆的算法
  11. 电子学推动计算机产业,自旋电子学和计算机硬件产业!-物理杂志.PDF
  12. Security2:角色和权限
  13. 升级主板和CPU后OpenGL初始化失败问题的解决
  14. 宽带提速后如何恰如其分的选择路由器?
  15. 关于Linux的应用层定时器
  16. 关于WIN7输入法的小问题
  17. java 创建一个date,java创建Date
  18. 仿真软件OriginPro之《文献图片取点方法》
  19. spectre13 matlab,惠普全新幽灵系列Spectre 13
  20. MongoDB与亚马逊云科技扩大全球合作

热门文章

  1. 手把手带你从零开始完整开发经典游戏【俄罗斯方块】,全部逻辑只用不到200行代码。
  2. Android WebView实现长截图
  3. 智能陈桥输入法软件测试,智能陈桥拼音输入法
  4. user_agent浏览器头部
  5. 解决ThinkPad早期笔记本Broadcom博通系列无线网卡Win10掉线、受限、速度慢问题(ThinkPad E530为例)
  6. 服务器lnixs系统,Navicat for MySQL v12.1.19 强大的数据库管理和开发工具 _ 黑苹果乐园...
  7. Java实现文件上传和下载
  8. format mla_MLA Format MLA格式
  9. MongoDB下载速度慢的解决办法
  10. GB28181的NAT穿透