question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Single.subscribeWith is not disposed

See original GitHub issue

Rxjava version:

compile "io.reactivex.rxjava2:rxjava:2.1.6"

Example:

Disposable disposable = Single.just("123")
        .subscribeWith(new DisposableSingleObserver() {
            @Override
            public void onSuccess(Object o) {}

            @Override
            public void onError(Throwable e) {}
        });

System.out.println("Disposed: "  + disposable.isDisposed());

Output:

Disposed: false

Expected result: Disposable should be disposed.

Related issues:

  • #5160 : 2.x: Disposable returned from Single.subscribe() is not disposed after terminal event
  • #5276 : Single’s Disposable is not disposing

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

5reactions
akarnokdcommented, Oct 31, 2017

Since DisposableSingleObserver implements the SingleObserver interface as abstract methods, it can’t call dispose() for you and you have to call that from within onSuccess or onComplete. Therefore, you can either call the lambda subscribe() overload and get the isDisposed consistent with the state or define your abstract wrapper over DisposableSingleObserver.

In concept, once onSuccess or onError are called, the upstream is to be considered disposed thus there should be no reason to call dispose at that point. People often need side-effects when a source terminates or gets disposed, thus they use doOnDisposed and call dispose from onSuccess to trigger that cleanup. However, there is a more appropriate operator called doFinally that executes after terminal events or dispose calls, thus you don’t have to call dispose to cleanup a flow.

ResourceSingleObserver’s JavaDoc explains it a bit better though.

1reaction
akarnokdcommented, Oct 31, 2017

Upstream’s don’t care if your SingleObserver implements Disposable because unlike 1.x, dispose() travels upstream and never downstream. If a chain has resources, a terminal event will free those resources so you don’t have to call dispose. just has no resources associated.

The convenience observer classes, such as DisposableSingleObserver are provided so one can call dispose on it from any thread without the need to dig into the concurrency implications of such call.

isDisposed makes only sense on container types and inside operators that check if they should continue producing data or not.

Checking if a flow has terminated via isDisposed has two discouraged uses: trying to sleep-loop or busy-loop on it or having a completely synchronous flows that terminates once the execution returns from subscribe(). You have the latter case.

The DisposableSingleObserver keeps two abstract methods, onSuccess and onError from SingleObserver. You implement those methods and Single talks to the SingleObserver interface. There is nothing in between that would react to the method calls and make isDisposed return true - we don’t use aspect oriented programming in RxJava after all.

So either don’t rely on isDisposed or write another wrapper that implements onSuccess and onError, delegates some alternative abstract methods and then calls dispose() for you to get isDisposed return true:

public abstract class AbstractMySingleObserver<T> extends DisposableSingleObserver<T> {

    @Override
    public final void onSuccess(T item) {
        try {
            success(item);
        } finally {
            dispose();
        }
    }

    @Override
    public final void onError(Throwable ex) {
        try {
            error(ex);
        } finally {
            dispose();
        }
    }

    protected abstract void success(T item);

    protected abstract void error(Throwable ex);

}
Read more comments on GitHub >

github_iconTop Results From Across the Web

The result of subscribe is not used - Stack Overflow
The IDE does not know what potential effects your subscription can have when it's not disposed, so it treats it as potentially unsafe....
Read more >
The curious case of RxJava Disposables A.K.A. what happens ...
In this example, we are disposing the flow in Single#map which is followed by Single#flatMap . ... No values are received by the...
Read more >
DisposableSingleObserver (RxJava Javadoc 2.2.21)
Returns true if this resource has been disposed. protected void, onStart(). Called once the single upstream Disposable is set via onSubscribe.
Read more >
Single (RxJava Javadoc 2.2.13)
Concatenate the single values, in a non-overlapping fashion, ... action after this Single signals onSuccess or onError or gets disposed by the downstream....
Read more >
RxJava 2 (Disposing Subscriptions) · Kaushik Gopal's Site
interface Publisher<T> { // return type void (not Subscription like before) ... T> observer); } // Single implements SingleSource interface SingleSource<T> ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found