0

I have an observable:

public Observable<List<Conversation>> getConversationListObservable() {
    return Observable.create(emitter -> {
        List<Conversation> conversations = networkApi.getConversations();
        for (Conversation conversation : conversations) {
            if (emitter.isDisposed()) return;  // this will cause subscription to terminate.
            List<User> users = networkApi.getUserList(conversation.getId());
            conversation.setUsers(users);
        }
        emitter.onNext(conversations);
        emitter.onComplete();
    });
}

which is used in androidx.lifecycle.ViewModel class:

public class ConversationViewModel extends ViewModel {
    private CompositeDisposable disposables = new CompositeDisposable();
    ....
    public void fetchConversationList(){
        disposables.add(repository.getConversationListObservable()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(this::setConversations, this::onError));
    }
}

When I go away from the screen with a list of Conversation, this observable is disposed, but I have a warning in logcat from RxJavaPlugins.setErrorHandler placed in my Application class:

W/RxJavaPlugins.setErrorHandler - Undeliverable exception received, not sure what to do: java.lang.InterruptedException

on networkApi.getUserList call. Seems like when I make this network call my subscriber is not disposed at the beginning of the network call and is already disposed when I am getting response on the call. Is there a way to do not get InterruptedException in RxJavaPlugins.setErrorHandler except of removing this plugin from Application class?

P.S.: Stack trace looks like:

2019-11-24 23:28:00.152 18051-18343/com.example W/RxJavaPlugins.setErrorHandler - Undeliverable exception received, not sure what to do: java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1036)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1327)
    at scala.concurrent.impl.Promise$DefaultPromise.tryAwait(Promise.scala:212)
    at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:222)
    at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:227)
    at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:190)
    at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
    at scala.concurrent.Await$.result(package.scala:190)
    at com.example.client.Client.sendRequest(Client.scala:61)
    at com.example.ui.Repository.provideClient(Repository.java:205)
    at com.example.ui.Repository.fetchUser(Repository.java:981)
    at com.example.ui.Repository.fetchUserWithRole(Repository.java:987)
    at com.example.ui.Repository.access$2400(Repository.java:95)
    at com.example.ui.Repository$11.lambda$createCall$1$Repository$11(Repository.java:912)
    at com.example.ui.-$$Lambda$Repository$11$8ZJhKkqn7hg2E6f5A5NBX1EeUPY.subscribe(lambda)
    at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)
    at io.reactivex.Observable.subscribe(Observable.java:12267)
    at io.reactivex.internal.operators.observable.ObservableOnErrorNext.subscribeActual(ObservableOnErrorNext.java:38)
    at io.reactivex.Observable.subscribe(Observable.java:12267)
    at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
    at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
    at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
    at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)

It is a stack trace from the real code, but I have simplified the code for the present question. Client.sendRequest in this stack trace corresponds to networkApi.getUserList in the simplified example.

isabsent
  • 3,683
  • 3
  • 25
  • 46
  • Can you print the stack trace of this `Undeliverable exception received`? – Pavel Poley Nov 24 '19 at 16:50
  • Question has been updated with a stack trace. – isabsent Nov 24 '19 at 17:15
  • When you are not navigates to another screen there are no exceptions at all? – Pavel Poley Nov 24 '19 at 17:21
  • No exceptions (not exceptions - just warnings) at all. If I wait enough time to load all users in all conversations I don't have warnings in the stack trace after navigate to another screen. – isabsent Nov 24 '19 at 17:24
  • So, if a subscriber is not disposed at the beginning of the network call and is already disposed when getting response on the call the exception always be thrown and the choice is only the place where I can catch it? – isabsent Nov 24 '19 at 17:45
  • yes, and as an encouragement, from the official [docs](https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling): "If the library/code already did this, the undeliverable InterruptedExceptions should stop now. If this pattern was not employed before, we encourage updating the code/library in question.". Also in a comment for the InterruptedExceptions catch in the setErrorHandler code: "fine, some blocking code was interrupted by a dispose call" – Gustavo Pagani Nov 24 '19 at 17:55

0 Answers0