请考虑一种情况,在这种情况下,我们有一个流在发射字符串,并且希望将字符串保存在文件中。
我正在使用PublishSubject,它可以正常工作:
Subject<String> stream = PublishSubject.create();
stream.subscribe(str -> saveFile(str));
mReverseGeocoderStream.onNext("some-string1")
mReverseGeocoderStream.onNext("some-string2")
但是,这不起作用(仅发送some-string2
)
Subject<String> stream = PublishSubject.create();
mReverseGeocoderStream.onNext("some-string1")
stream.subscribe(str -> saveFile(str));
mReverseGeocoderStream.onNext("some-string2")
是否有办法使第二种情况也起作用?
也就是说,我们可以更改PublishSubject
来确保它缓冲事件直到订阅者使用它们吗?
请注意,BehaviorSubject
不是一个选项,因为重新订阅会导致另一个文件保存。它没有“消费事件”的概念。
我发现UnicastSubject几乎是我想要的,除了,当我取消订阅并随后重新订阅其他订阅者时,它失败,并出现IllegalStateException。
用例:
假设我们有一个android应用。它发出网络请求,在网络请求的后面,需要显示一个对话框。在发出请求时,用户将使应用程序后台运行。此时,我们将取消订阅正在监听信号以显示对话框的观察者。
网络请求返回,并发出信号显示对话框已触发到流。目前尚无人在听。用户将应用程序前台化。新订户将附加到网络请求管理器(ViewModel)。在这一点上,我希望将“未消耗”的信号传递给订户。
注意:我不能使用行为主题。如果执行此操作,则每次用户在后台运行应用程序时,都会显示该对话框。我希望事件在显示对话框后被消耗并结束。
答案 0 :(得分:0)
进行了更多研究,发现了这一点:
https://gist.github.com/xsveda/8c556516079fde97d04b4b7e14a18463
来自:Queue like Subject in RxJava
请注意,它使用中继,但是如果您不想引入其他依赖项,则可以轻松地用主题替换中继。
我对其他解决方案持开放态度,也许会批评为什么这种解决方案不是很好的解决方案。
/**
* Relay that buffers values when no Observer subscribed and replays them to Observer as requested. Such values are not replayed
* to any other Observer.
* <p>
* This relay holds an unbounded internal buffer.
* <p>
* This relay allows only a single Observer at a time to be subscribed to it.
* <p>
* If more than one Observer attempts to subscribe to this Relay at the same time, they
* will receive an IllegalStateException.
*
* @param <T> the value type received and emitted by this Relay subclass
*/
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);
}
}
}