Java技巧分享之利用RxJava打造可觀測(cè)數(shù)據(jù)RxLiveData
1. 問(wèn)題場(chǎng)景
在實(shí)際工作中,我們經(jīng)常需要在不同類(lèi)對(duì)象之間、不同模塊之間共享數(shù)據(jù),而這些數(shù)據(jù)通常是可改動(dòng)的,那么就可能發(fā)生一個(gè)問(wèn)題:當(dāng)數(shù)據(jù)變動(dòng)時(shí),相關(guān)對(duì)象或模塊并不知道,沒(méi)有及時(shí)更新數(shù)據(jù)。這時(shí)候,我們希望數(shù)據(jù)改變時(shí)可以通知其他模塊同步更新,實(shí)現(xiàn)一個(gè)類(lèi)似數(shù)據(jù)之間聯(lián)動(dòng)的效果。最容易想到的應(yīng)該就是監(jiān)聽(tīng)回調(diào)的觀察者模式,下面給出一種以前見(jiàn)過(guò)的、不太優(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)聽(tīng)重新實(shí)現(xiàn)一遍);
- 增加內(nèi)存溢出的風(fēng)險(xiǎn)(調(diào)用
addUserListener
的人可能忘記調(diào)用removeUserListener
); - setter方法的污染(做了多余的事情)。
面對(duì)這樣的問(wèn)題,RxJava、JDK中的Observable和Flow API還有Android里的LiveData都給出了可用的實(shí)現(xiàn)方式,在實(shí)際開(kāi)發(fā)中,感覺(jué)并不是那么方便。而本文要介紹的是我利用RxJava打造一個(gè)更加方便的可觀測(cè)對(duì)象工具類(lèi)--RxLiveData(代碼見(jiàn)最底部)。
2. 使用示例
先來(lái)看一個(gè)比較短的完整示例:
/* 測(cè)試用的 Java Bean 數(shù)據(jù)類(lèi)*/ class User { //...... Java Bean 的字段略 } /* 一個(gè)單例 */ 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() { //訂閱可觀測(cè)對(duì)象,使得數(shù)據(jù)發(fā)生改變時(shí)可以被回調(diào) UserManager.getInstance().getUserData().getObservable() .subscribe((User user) -> {//使用lambda版 update(user);// 每次用戶(hù)信息改變,這里會(huì)被調(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ù),這時(shí)候A和B中的對(duì)應(yīng)方法會(huì)被調(diào)用 UserManager.getInstance().getUserData().postData(new User()); } }
這里模擬UserManager
的數(shù)據(jù)在A
和B
類(lèi)的對(duì)象之間共享,當(dāng)UserManager
的內(nèi)容發(fā)生改變時(shí),可以通知到A
和B
,執(zhí)行相應(yīng)操作。
這時(shí)如果還想給UserManager
增加一個(gè)數(shù)據(jù),例如一個(gè)long
類(lèi)型的time
,只需要按照下面這樣添加一個(gè)屬性和一個(gè)getter方法就可以了:
private final RxLiveData<Long> timeData = new RxLiveData<>(); public RxLiveData<Long> getTimeData() { return timeData; }
如果是在Android應(yīng)用開(kāi)發(fā)中,還可以借助RxAndroid和RxLifecycle的功能,來(lái)控制回調(diào)的執(zhí)行線程并在界面銷(xiāo)毀時(shí)取消訂閱,例如:
userManager.getUserData().getObservable() .compose(bindUntilEvent(ActivityEvent.DESTROY))//指定在onDestroy回調(diào)時(shí)取消訂閱 .observeOn(AndroidSchedulers.mainThread())//指定主線程 .subscribe(user -> { }, Throwable::printStackTrace);
3. 主要方法介紹
3.1 getObservable 方法
方法簽名:public Observable<T> getObservable()
這個(gè)方法用于獲取RxJava的Observable
,進(jìn)而對(duì)數(shù)據(jù)進(jìn)行訂閱,還可以得到RxJava相關(guān)功能的支持(例如,Stream 操作,指定線程,控制生命周期等等)。
3.2 postData 方法
方法簽名:public void postData(T value)
這個(gè)方法用于更新數(shù)據(jù)。它會(huì)更新存在在當(dāng)前RxLiveData對(duì)象中的數(shù)據(jù),并通過(guò)RxJava的ObservableEmitter
觸發(fā)觀察者的回調(diào)。
注意:當(dāng)參數(shù)為null
時(shí),由于RxJava會(huì)對(duì)null
拋出異常,所以這里的實(shí)現(xiàn)方式是在判斷為null
的時(shí)候只存儲(chǔ)數(shù)據(jù),不觸發(fā)觀察者的回調(diào)。
3.3 getValue 方法
方法簽名:public T getValue()
這個(gè)方法僅用于獲得存在在當(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的請(qǐng)改為該版本的包名 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打造可觀測(cè)數(shù)據(jù)RxLiveData的文章就介紹到這了,更多相關(guān)Java RxJava可觀測(cè)數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于SpringBoot實(shí)現(xiàn)驗(yàn)證碼功能的代碼及思路
SpringBoot技術(shù)是目前市面上從事JavaEE企業(yè)級(jí)開(kāi)發(fā)過(guò)程中使用量最大的技術(shù),下面這篇文章主要給大家介紹了如何基于SpringBoot實(shí)現(xiàn)驗(yàn)證碼功能的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07分析講解SpringMVC注解配置如何實(shí)現(xiàn)
這篇文章主要介紹了本文要介紹用注解方式代替web.xml與SpringMVC的配置文件,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05dubbo如何設(shè)置連接zookeeper權(quán)限
這篇文章主要介紹了dubbo如何設(shè)置連接zookeeper權(quán)限問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05java保證一個(gè)方法只能執(zhí)行一次的問(wèn)題
這篇文章主要介紹了java保證一個(gè)方法只能執(zhí)行一次的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08SpringBoot項(xiàng)目yml配置文件不自動(dòng)提示解決方案
這篇文章主要介紹了SpringBoot項(xiàng)目配置文件.yaml/.yml文件編寫(xiě)時(shí)沒(méi)有自動(dòng)提示的解決方案,文章通過(guò)圖文結(jié)合的方式給大家講解的非常詳細(xì),需要的朋友可以參考下2024-06-06前端如何調(diào)用后端接口進(jìn)行數(shù)據(jù)交互詳解(axios和SpringBoot)
一般來(lái)講前端不會(huì)給后端接口,而是后端給前端接口的情況比較普遍,下面這篇文章主要給大家介紹了關(guān)于前端如何調(diào)用后端接口進(jìn)行數(shù)據(jù)交互的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03關(guān)于解決雪花算法生成的ID傳輸前端后精度丟失問(wèn)題
這篇文章主要介紹了關(guān)于解決雪花算法生成的ID傳輸前端后精度丟失問(wèn)題,雪花算法生成的ID傳輸?shù)角岸藭r(shí),會(huì)出現(xiàn)后三位精度丟失,本文提供了解決思路,需要的朋友可以參考下2023-03-03