Java技巧分享之利用RxJava打造可觀測數(shù)據(jù)RxLiveData
1. 問題場景
在實(shí)際工作中,我們經(jīng)常需要在不同類對象之間、不同模塊之間共享數(shù)據(jù),而這些數(shù)據(jù)通常是可改動的,那么就可能發(fā)生一個問題:當(dāng)數(shù)據(jù)變動時,相關(guān)對象或模塊并不知道,沒有及時更新數(shù)據(jù)。這時候,我們希望數(shù)據(jù)改變時可以通知其他模塊同步更新,實(shí)現(xiàn)一個類似數(shù)據(jù)之間聯(lián)動的效果。最容易想到的應(yīng)該就是監(jiān)聽回調(diào)的觀察者模式,下面給出一種以前見過的、不太優(yōu)雅的實(shí)現(xiàn):
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);
}
}
}這種方式有以下缺點(diǎn):
- 不具備復(fù)用性(每次添加新的數(shù)據(jù)都要把回調(diào)監(jiān)聽重新實(shí)現(xiàn)一遍);
- 增加內(nèi)存溢出的風(fēng)險(調(diào)用
addUserListener的人可能忘記調(diào)用removeUserListener); - setter方法的污染(做了多余的事情)。
面對這樣的問題,RxJava、JDK中的Observable和Flow API還有Android里的LiveData都給出了可用的實(shí)現(xiàn)方式,在實(shí)際開發(fā)中,感覺并不是那么方便。而本文要介紹的是我利用RxJava打造一個更加方便的可觀測對象工具類--RxLiveData(代碼見最底部)。
2. 使用示例
先來看一個比較短的完整示例:
/* 測試用的 Java Bean 數(shù)據(jù)類*/
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() {
//訂閱可觀測對象,使得數(shù)據(jù)發(fā)生改變時可以被回調(diào)
UserManager.getInstance().getUserData().getObservable()
.subscribe((User user) -> {//使用lambda版
update(user);// 每次用戶信息改變,這里會被調(diào)用
});
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中的數(shù)據(jù),這時候A和B中的對應(yīng)方法會被調(diào)用
UserManager.getInstance().getUserData().postData(new User());
}
}這里模擬UserManager的數(shù)據(jù)在A和B類的對象之間共享,當(dāng)UserManager的內(nèi)容發(fā)生改變時,可以通知到A和B,執(zhí)行相應(yīng)操作。
這時如果還想給UserManager增加一個數(shù)據(jù),例如一個long類型的time,只需要按照下面這樣添加一個屬性和一個getter方法就可以了:
private final RxLiveData<Long> timeData = new RxLiveData<>();
public RxLiveData<Long> getTimeData() {
return timeData;
}如果是在Android應(yīng)用開發(fā)中,還可以借助RxAndroid和RxLifecycle的功能,來控制回調(diào)的執(zhí)行線程并在界面銷毀時取消訂閱,例如:
userManager.getUserData().getObservable()
.compose(bindUntilEvent(ActivityEvent.DESTROY))//指定在onDestroy回調(diào)時取消訂閱
.observeOn(AndroidSchedulers.mainThread())//指定主線程
.subscribe(user -> {
}, Throwable::printStackTrace);3. 主要方法介紹
3.1 getObservable 方法
方法簽名:public Observable<T> getObservable()
這個方法用于獲取RxJava的Observable,進(jìn)而對數(shù)據(jù)進(jìn)行訂閱,還可以得到RxJava相關(guān)功能的支持(例如,Stream 操作,指定線程,控制生命周期等等)。
3.2 postData 方法
方法簽名:public void postData(T value)
這個方法用于更新數(shù)據(jù)。它會更新存在在當(dāng)前RxLiveData對象中的數(shù)據(jù),并通過RxJava的ObservableEmitter觸發(fā)觀察者的回調(diào)。
注意:當(dāng)參數(shù)為null時,由于RxJava會對null拋出異常,所以這里的實(shí)現(xiàn)方式是在判斷為null的時候只存儲數(shù)據(jù),不觸發(fā)觀察者的回調(diào)。
3.3 getValue 方法
方法簽名:public T getValue()
這個方法僅用于獲得存在在當(dāng)前RxLiveData中的數(shù)據(jù)。
3.4 optValue 方法
方法簽名:public Optional<T> optValue()
getValue方法的Optional版本。
4. 完整實(shí)現(xiàn)
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);
}
}到此這篇關(guān)于Java技巧分享之利用RxJava打造可觀測數(shù)據(jù)RxLiveData的文章就介紹到這了,更多相關(guān)Java RxJava可觀測數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
實(shí)現(xiàn)一個規(guī)則引擎的可視化具體方案
項(xiàng)目原因需要用到規(guī)則引擎,但是發(fā)現(xiàn)大部分不可以自由的進(jìn)行規(guī)則定義,通過不斷嘗試變換關(guān)鍵字在搜索引擎搜索,最終在stackoverflow找到了一個探討這個問題的帖子,特此將帖子中提到的方案分享一下,如果你跟我一樣在研究同樣的問題,也許對你有用2021-04-04
一文總結(jié)Java實(shí)現(xiàn)TXT轉(zhuǎn)PDF的三種高效方案
將 TXT 文本轉(zhuǎn)換為 PDF 并不繁瑣,本篇指南將介紹根據(jù)三種實(shí)用的轉(zhuǎn)換技巧,包括手動操作、在線工具和程序化自動處理,助你輕松搞定文檔遷移,希望對大家有所幫助2026-02-02
MyEclipse打開文件跳轉(zhuǎn)到notepad打開問題及解決方案
windows系統(tǒng)打開README.md文件,每次都需要右鍵選擇notepad打開,感覺很麻煩,然后就把README.md文件打開方式默認(rèn)選擇了notepad,這樣每次雙擊就能打開,感覺很方便,這篇文章主要介紹了MyEclipse打開文件跳轉(zhuǎn)到notepad打開問題,需要的朋友可以參考下2024-03-03
Java中日期的加減&String Date Calendar的相互轉(zhuǎn)換方式
這篇文章主要介紹了Java中日期的加減&String Date Calendar的相互轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-05-05
RocketMQ中消費(fèi)者的消費(fèi)進(jìn)度管理
這篇文章主要介紹了RocketMQ中消費(fèi)者的消費(fèi)進(jìn)度管理,業(yè)務(wù)實(shí)現(xiàn)消費(fèi)回調(diào)的時候,當(dāng)且僅當(dāng)此回調(diào)函數(shù)返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS ,RocketMQ才會認(rèn)為這批消息(默認(rèn)是1條)是消費(fèi)完成的,需要的朋友可以參考下2023-10-10
IDEA配置Tomcat后,控制臺tomcat?catalina?log出現(xiàn)亂碼問題
本文介紹了如何通過設(shè)置Tomcat和IDEA的編碼格式來解決編碼問題,首先嘗試修改Tomcat的logging.properties文件中的編碼設(shè)置,如果未解決問題,則調(diào)整IDEA的編碼設(shè)置,通過修改vmoptions文件來全局設(shè)置IDEA的編碼格式,作者分享了個人成功解決問題的方法和步驟,供其他開發(fā)者參考2024-09-09
Java 調(diào)用Restful API接口的幾種方式(HTTPS)
這篇文章主要介紹了Java 調(diào)用Restful API接口的幾種方式(HTTPS),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02

