Java技巧分享之利用RxJava打造可观测数据RxLiveData

 更新时间:2023年06月09日 15:22:24   作者:乐征skyline  
这篇文章主要来和大家分享一个Java技巧,那就是利用RxJava打造可观测数据RxLiveData,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下

1. 问题场景

在实际工作中,我们经常需要在不同类对象之间、不同模块之间共享数据,而这些数据通常是可改动的,那么就可能发生一个问题:当数据变动时,相关对象或模块并不知道,没有及时更新数据。这时候,我们希望数据改变时可以通知其他模块同步更新,实现一个类似数据之间联动的效果。最容易想到的应该就是监听回调的观察者模式,下面给出一种以前见过的、不太优雅的实现:

class User {
    //...... Java Bean 的字段略
}
interface Listener {
    void onUserUpdated(User user);
}
class UserManager {
    private static UserManager manager = new UserManager();
    private UserManager() {
    }
    public static UserManager getInstance() {
        return manager;
    }
    private User user;
    private List<Listener> listeners = new LinkedList<>();
    public void addUserListener(Listener listener) {
        listeners.add(listener);
    }
    public void removeUserListener(Listener listener) {
        listeners.remove(listener);
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
        for (Listener listener : listeners) {
            listener.onUserUpdated(this.user);
        }
    }
}

这种方式有以下缺点:

  • 不具备复用性(每次添加新的数据都要把回调监听重新实现一遍);
  • 增加内存溢出的风险(调用addUserListener的人可能忘记调用removeUserListener);
  • setter方法的污染(做了多余的事情)。

面对这样的问题,RxJava、JDK中的Observable和Flow API还有Android里的LiveData都给出了可用的实现方式,在实际开发中,感觉并不是那么方便。而本文要介绍的是我利用RxJava打造一个更加方便的可观测对象工具类--RxLiveData(代码见最底部)。

2. 使用示例

先来看一个比较短的完整示例:

/* 测试用的 Java Bean 数据类*/
class User {
    //...... Java Bean 的字段略
}
/* 一个单例 */
class UserManager {
    private static final UserManager manager = new UserManager();
    private UserManager() {
    }
    public static UserManager getInstance() {
        return manager;
    }
    private final RxLiveData<User> userData = new RxLiveData<>();
    public RxLiveData<User> getUserData() {
        return userData;
    }
}
class A {
    public void init() {
        //订阅可观测对象,使得数据发生改变时可以被回调
        UserManager.getInstance().getUserData().getObservable()
                .subscribe((User user) -> {//使用lambda版
                    update(user);// 每次用户信息改变,这里会被调用
                });
        update(UserManager.getInstance().getUserData().getValue());
    }
    private void update(User user) {
        System.out.println("user changed");
    }
}
class B{
    public B() {
        UserManager.getInstance().getUserData().getObservable().subscribe(this::update);//方法引用版
    }
    private void update(User user) {
        System.out.println("user changed");
    }
}
public class Main {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        a.init();
        B b = new B();
        //更新UserManager中的数据,这时候A和B中的对应方法会被调用
        UserManager.getInstance().getUserData().postData(new User());
    }
}

这里模拟UserManager的数据在AB类的对象之间共享,当UserManager的内容发生改变时,可以通知到AB,执行相应操作。

这时如果还想给UserManager增加一个数据,例如一个long类型的time,只需要按照下面这样添加一个属性和一个getter方法就可以了:

private final RxLiveData<Long> timeData = new RxLiveData<>();
public RxLiveData<Long> getTimeData() {
    return timeData;
}

如果是在Android应用开发中,还可以借助RxAndroid和RxLifecycle的功能,来控制回调的执行线程并在界面销毁时取消订阅,例如:

userManager.getUserData().getObservable()
        .compose(bindUntilEvent(ActivityEvent.DESTROY))//指定在onDestroy回调时取消订阅
        .observeOn(AndroidSchedulers.mainThread())//指定主线程
        .subscribe(user -> {
        }, Throwable::printStackTrace);

3. 主要方法介绍

3.1 getObservable 方法

方法签名public Observable<T> getObservable()

这个方法用于获取RxJava的Observable,进而对数据进行订阅,还可以得到RxJava相关功能的支持(例如,Stream 操作,指定线程,控制生命周期等等)。

3.2 postData 方法

方法签名public void postData(T value)

这个方法用于更新数据。它会更新存在在当前RxLiveData对象中的数据,并通过RxJava的ObservableEmitter触发观察者的回调。

注意:当参数为null时,由于RxJava会对null抛出异常,所以这里的实现方式是在判断为null的时候只存储数据,不触发观察者的回调。

3.3 getValue 方法

方法签名public T getValue()

这个方法仅用于获得存在在当前RxLiveData中的数据。

3.4 optValue 方法

方法签名public Optional<T> optValue()

getValue方法的Optional版本。

4. 完整实现

import io.reactivex.rxjava3.core.Observable;//如果用的是RxJava2的请改为该版本的包名
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.disposables.Disposable;
import java.util.Optional;
public class RxLiveData<T> {
    private final Observable<T> observable;
    private Disposable disposable;
    private T value;
    private ObservableEmitter<T> emitter;
    public RxLiveData() {
        observable = Observable
                .create((ObservableEmitter<T> emitter) -> this.emitter = emitter)
                .publish()
                .autoConnect(0, disposable -> this.disposable = disposable);
    }
    public Observable<T> getObservable() {
        return observable;
    }
    public void postData(T value) {
        this.value = value;
        if (emitter != null && value != null) {
            emitter.onNext(value);
        }
    }
    public T getValue() {
        return value;
    }
    public Optional<T> optValue() {
        return Optional.ofNullable(value);
    }
}

到此这篇关于Java技巧分享之利用RxJava打造可观测数据RxLiveData的文章就介绍到这了,更多相关Java RxJava可观测数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 实现一个规则引擎的可视化具体方案

    实现一个规则引擎的可视化具体方案

    项目原因需要用到规则引擎,但是发现大部分不可以自由的进行规则定义,通过不断尝试变换关键字在搜索引擎搜索,最终在stackoverflow找到了一个探讨这个问题的帖子,特此将帖子中提到的方案分享一下,如果你跟我一样在研究同样的问题,也许对你有用
    2021-04-04
  • 一文总结Java实现TXT转PDF的三种高效方案

    一文总结Java实现TXT转PDF的三种高效方案

    将 TXT 文本转换为 PDF 并不繁琐,本篇指南将介绍根据三种实用的转换技巧,包括手动操作、在线工具和程序化自动处理,助你轻松搞定文档迁移,希望对大家有所帮助
    2026-02-02
  • 新手也能看懂的SpringBoot异步编程指南(简单易懂)

    新手也能看懂的SpringBoot异步编程指南(简单易懂)

    这篇文章主要介绍了新手也能看懂的SpringBoot异步编程指南(简单易懂),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • MyEclipse打开文件跳转到notepad打开问题及解决方案

    MyEclipse打开文件跳转到notepad打开问题及解决方案

    windows系统打开README.md文件,每次都需要右键选择notepad打开,感觉很麻烦,然后就把README.md文件打开方式默认选择了notepad,这样每次双击就能打开,感觉很方便,这篇文章主要介绍了MyEclipse打开文件跳转到notepad打开问题,需要的朋友可以参考下
    2024-03-03
  • Java中日期的加减&String Date Calendar的相互转换方式

    Java中日期的加减&String Date Calendar的相互转换方式

    这篇文章主要介绍了Java中日期的加减&String Date Calendar的相互转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • 浅谈Spring单例Bean与单例模式的区别

    浅谈Spring单例Bean与单例模式的区别

    这篇文章主要介绍了浅谈Spring单例Bean与单例模式的区别,具有一定借鉴价值,需要的朋友可以参考下
    2017-12-12
  • RocketMQ中消费者的消费进度管理

    RocketMQ中消费者的消费进度管理

    这篇文章主要介绍了RocketMQ中消费者的消费进度管理,业务实现消费回调的时候,当且仅当此回调函数返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS ,RocketMQ才会认为这批消息(默认是1条)是消费完成的,需要的朋友可以参考下
    2023-10-10
  • IDEA配置Tomcat后,控制台tomcat catalina log出现乱码问题

    IDEA配置Tomcat后,控制台tomcat catalina log出现乱码问题

    本文介绍了如何通过设置Tomcat和IDEA的编码格式来解决编码问题,首先尝试修改Tomcat的logging.properties文件中的编码设置,如果未解决问题,则调整IDEA的编码设置,通过修改vmoptions文件来全局设置IDEA的编码格式,作者分享了个人成功解决问题的方法和步骤,供其他开发者参考
    2024-09-09
  • java中接口幂等性的五种实现方法

    java中接口幂等性的五种实现方法

    在java中保证接口幂等性,即多次调用同一接口产生与单次调用相同的结果,不会引发副作用,需要结合业务场景选择合适的方案,下面就来介绍五种实现方法,感兴趣的可以了解一下
    2025-09-09
  • Java 调用Restful API接口的几种方式(HTTPS)

    Java 调用Restful API接口的几种方式(HTTPS)

    这篇文章主要介绍了Java 调用Restful API接口的几种方式(HTTPS),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02

最新评论