在dispose()之后,无法两次将相同的DisposableObserver与subscribeWith一起使用

时间:2019-09-22 12:59:18

标签: kotlin rx-java2

代码(Kotlin)非常简单,但是我不明白,为什么我不能使用同一对象再次订阅?

val x = Observable.interval(1L, TimeUnit.SECONDS, Schedulers.io())
    .map {
        println("emitting=$it")
        it.toString()
    }.publish().autoConnect()

val o = object : DisposableObserver<String>() {
    override fun onComplete() {}
    override fun onNext(t: String) = println("O:=$t")
    override fun onError(e: Throwable) {}
}
println("---------- subscribe ----------")
val s2 = x.subscribeWith(o)

sleepSeconds(2)
println("---------- dispose ----------")
s2.dispose()

sleepSeconds(2)
println("---------- subscribe again ----------")
x.subscribeWith(o) //<<-- This doesn't work!!!!

sleepSeconds(5)

控制台输出为:

---------- subscribe ----------
emitting=0
O:=0
emitting=1
O:=1
---------- dispose ----------
emitting=2
emitting=3
---------- subscribe again ----------
emitting=4
emitting=5
etc.....

当我创建类DisposableObserver的新实例时,它运行良好。

1 个答案:

答案 0 :(得分:1)

DisposableObserver设计为只能订阅一次javadoc。当您在DisposableObserver的内部查看时,您会看到AtomicReference upstream,当观察者订阅时,它可以节省当前的一次性物品。

public abstract class DisposableObserver<T> implements Observer<T>, Disposable {

    final AtomicReference<Disposable> upstream = new AtomicReference<Disposable>();

    @Override
    public final void onSubscribe(@NonNull Disposable d) {
        if (EndConsumerHelper.setOnce(this.upstream, d, getClass())) {
            onStart();
        }
    }
// rest of code

EndConsumerHelper.setOnce确保DisposableObserver仅订阅一次。如果upstream已被处置,则无法设置其他upstream

public static boolean setOnce(AtomicReference<Disposable> upstream, Disposable next, Class<?> observer) {
        ObjectHelper.requireNonNull(next, "next is null");
        if (!upstream.compareAndSet(null, next)) { 
            next.dispose();  // dispose next if there is set upstream previously 
            if (upstream.get() != DisposableHelper.DISPOSED) {
                reportDoubleSubscription(observer);
            }
            return false;
        }
        return true;  
    }

这就是为什么您不能使用相同的DisposableObserver实例重新订阅,但可以使用新实例工作的原因。