Rx java RxJava中的类队列主题
我正在寻找一个可以:Rx java RxJava中的类队列主题,rx-java,Rx Java,我正在寻找一个可以: 如果没有订阅服务器,则可以接收项目并将其保存在队列或缓冲区中 一旦我们有了订阅者,所有的物品都会被消耗掉,再也不会发出 我可以订阅/取消订阅主题 BehaviorSubject几乎可以完成这项工作,但它保留了最后观察到的项 更新 根据公认的答案,我为单个观察项目制定了类似的解决方案。还添加了取消订阅部分,以避免内存泄漏 class LastEventObservable private constructor( private val onSubscribe
BehaviorSubject
几乎可以完成这项工作,但它保留了最后观察到的项
更新
根据公认的答案,我为单个观察项目制定了类似的解决方案。还添加了取消订阅部分,以避免内存泄漏
class LastEventObservable private constructor(
private val onSubscribe: OnSubscribe<Any>,
private val state: State
) : Observable<Any>(onSubscribe) {
fun emit(value: Any) {
if (state.subscriber.hasObservers()) {
state.subscriber.onNext(value)
} else {
state.lastItem = value
}
}
companion object {
fun create(): LastEventObservable {
val state = State()
val onSubscribe = OnSubscribe<Any> { subscriber ->
just(state.lastItem)
.filter { it != null }
.doOnNext { subscriber.onNext(it) }
.doOnCompleted { state.lastItem = null }
.subscribe()
val subscription = state.subscriber.subscribe(subscriber)
subscriber.add(Subscriptions.create { subscription.unsubscribe() })
}
return LastEventObservable(onSubscribe, state)
}
}
private class State {
var lastItem: Any? = null
val subscriber = PublishSubject.create<Any>()
}
}
class LastEventObservable私有构造函数(
私人val onSubscribe:onSubscribe,
私有val状态:状态
):可观察(未订阅){
乐趣释放(值:任意){
if(state.subscriber.hasObservators()){
state.subscriber.onNext(值)
}否则{
state.lastItem=值
}
}
伴星{
fun create():LastEventObservable{
val state=state()
val onSubscribe=onSubscribe{subscriber->
just(state.lastItem)
.filter{it!=null}
.doOnNext{subscriber.onNext(it)}
.doOnCompleted{state.lastItem=null}
.subscribe()
val subscription=state.subscriber.subscribe(订户)
subscriber.add(Subscriptions.create{subscription.unsubscripte()})
}
返回LastEventObservable(onSubscribe,state)
}
}
私有阶级国家{
var lastItem:有吗?=null
val subscriber=PublishSubject.create()
}
}
我创建了一个定制的Observable,用于包装发布主题,并在没有附加订阅者的情况下处理发射缓存,从而达到了预期的效果。看看吧
public class ExampleUnitTest {
@Test
public void testSample() throws Exception {
MyCustomObservable myCustomObservable = new MyCustomObservable();
myCustomObservable.emit("1");
myCustomObservable.emit("2");
myCustomObservable.emit("3");
Subscription subscription = myCustomObservable.subscribe(System.out::println);
myCustomObservable.emit("4");
myCustomObservable.emit("5");
subscription.unsubscribe();
myCustomObservable.emit("6");
myCustomObservable.emit("7");
myCustomObservable.emit("8");
myCustomObservable.subscribe(System.out::println);
}
}
class MyCustomObservable extends Observable<String> {
private static PublishSubject<String> publishSubject = PublishSubject.create();
private static List<String> valuesCache = new ArrayList<>();
protected MyCustomObservable() {
super(subscriber -> {
Observable.from(valuesCache)
.doOnNext(subscriber::onNext)
.doOnCompleted(valuesCache::clear)
.subscribe();
publishSubject.subscribe(subscriber);
});
}
public void emit(String value) {
if (publishSubject.hasObservers()) {
publishSubject.onNext(value);
} else {
valuesCache.add(value);
}
}
}
公共类ExampleUnitTest{
@试验
public void testSample()引发异常{
MyCustomObservable MyCustomObservable=新的MyCustomObservable();
myCustomObservable.emit(“1”);
myCustomObservable.emit(“2”);
myCustomObservable.emit(“3”);
订阅订阅=myCustomObservable.subscribe(System.out::println);
myCustomObservable.emit(“4”);
myCustomObservable.emit(“5”);
订阅。取消订阅();
myCustomObservable.emit(“6”);
myCustomObservable.emit(“7”);
myCustomObservable.emit(“8”);
myCustomObservable.subscribe(System.out::println);
}
}
类MyCustomObservable扩展了Observable{
私有静态PublishSubject PublishSubject=PublishSubject.create();
私有静态列表valuesCache=newarraylist();
受保护的MyCustomObservable(){
超级(订户->{
可观察。来自(valuesCache)
.doOnNext(订户::onNext)
.doOnCompleted(valuesCache::clear)
.subscribe();
publishSubject.订阅(订户);
});
}
公共void发出(字符串值){
if(publishSubject.hasObservators()){
publishSubject.onNext(值);
}否则{
添加(值);
}
}
}
希望能有帮助
诚挚的问候。
< P>如果只想等待一个用户,请使用<代码> UnaseTase< /C>。但是注意,如果在中间不订阅,所有后续的队列项都将丢失。 编辑: 一旦我们有了a订阅者,所有的物品都会被消耗掉,再也不会发出对于多个订阅者,请使用
ReplaySubject
我遇到了类似的问题,我的要求是:
- 应支持在没有观察员订阅时重播值
- 一次只允许订阅一个观察者
- 当第一个观察者被释放时,应该允许另一个观察者订阅
public final class CacheRelay<T> extends Relay<T> {
private final ConcurrentLinkedQueue<T> queue = new ConcurrentLinkedQueue<>();
private final PublishRelay<T> relay = PublishRelay.create();
private CacheRelay() {
}
public static <T> CacheRelay<T> create() {
return new CacheRelay<>();
}
@Override
public void accept(T value) {
if (relay.hasObservers()) {
relay.accept(value);
} else {
queue.add(value);
}
}
@Override
public boolean hasObservers() {
return relay.hasObservers();
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
if (hasObservers()) {
EmptyDisposable.error(new IllegalStateException("Only a single observer at a time allowed."), observer);
} else {
for (T element; (element = queue.poll()) != null; ) {
observer.onNext(element);
}
relay.subscribeActual(observer);
}
}
}
公共最终类缓存中继扩展中继{
私有最终ConcurrentLinkedQueue队列=新ConcurrentLinkedQueue();
private final PublishRelay relay=PublishRelay.create();
专用缓存中继(){
}
公共静态缓存中继创建(){
返回新的CacheRelay();
}
@凌驾
公共无效接受(T值){
if(relay.hasObservators()){
继电器。接受(值);
}否则{
添加(值);
}
}
@凌驾
公共布尔hasObservators(){
返回继电器;
}
@凌驾
受保护的void subscribeActual(observer)应该可能有多个订阅者。@MartynasJurkus您可以将UnicastSubject
与.publish().autoConnect()
一起使用,但您不能在第一次取消订阅和第二次订阅之间“缓存”项目。但有一个库具有UnicastWorkerSubject
,允许这样做(但仍同时有一个订阅服务器)或允许多个订阅服务器的DispatchWorkSubject
。很遗憾,您无法指定缓冲区大小,因为在create()中
方法您可以传递capacityHint
,它不是指定的容量大小。这只是一个提示,因为SpscLinkedArrayQueue
和SPCLinkedArrayQueue
的实现,您看到我的答案了吗?请澄清您所说的“一旦我们有了订阅者,所有项目都将被消耗,并且永远不会再次发出”是什么意思-如果您有类似于:yourSource.take(1).subscribe()的内容,那么这是否应该删除源中的所有项目?不,这应该只消耗该项目。工作起来很有魅力。不过我不太喜欢这些静态变量:)我也是@MartynasJurkus。我们如何改进这个解决方案?请看我更新的问题。虽然我的代码是Kotlin。太棒了!我喜欢Koltin。你的最终解决方案比我最初的解决方案漂亮得多。我创建了一个库,灵感来自这篇文章:如何将工作移动到后台线程?我所做的所有操作