user2498079
user2498079

Reputation: 3012

Single observer is not calling onError()

I've written the following code in my MainActivity of an Android app. When I run the following code, it doesn't throw any exception and onError() also doesn't get called. However I see onSuccess: testing starts twice but I don't see onSuccess: testing ends. Why isn't onError() being called and/or why isn't the app crashing?

Single.timer(1000, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.computation())
                .subscribeWith(new DisposableSingleObserver<Long>() {
                    @Override
                    public void onSuccess(Long initiationTimeStamp) {
                        String s = null;
                        Log.d(TAG, "onSuccess: testing starts");
                        Log.d(TAG, "onSuccess:test  "+ s.isEmpty());
                        Log.d(TAG, "onSuccess: testing ends");
                    }

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

Upvotes: 1

Views: 1169

Answers (2)

Tomas Jablonskis
Tomas Jablonskis

Reputation: 4376

You are calling s.isEmpty() on a NULL String, thats why it ends at first print. That said onSuccess() does not throw anything, so it just stops execution when NullPointerException is thrown (it is silently handled inside RxJava for you). As soon as you subscribe to observable, you get initial value in onSuccess(), then if it changes or you resubscribe you get another value in onSuccess(), thats why it gets called twice. And because onError() is for errors occurring along the operation chain, you do not get an error in onSuccess() when exception is thrown.


This behaviour is intentional. According to Rx Contract, an observer should not receive both onSuccess() and onError(). You need to handle the exception in onSuccess() by yourself.

For example:

Single.timer(1000, TimeUnit.MILLISECONDS)
            .subscribeOn(Schedulers.computation())
            .subscribeWith(new DisposableSingleObserver<Long>() {
                @Override
                public void onSuccess(Long initiationTimeStamp) {
                    try {
                        String s = null;
                        Log.d(TAG, "onSuccess: testing starts");
                        Log.d(TAG, "onSuccess:test  "+ s.isEmpty());
                        Log.d(TAG, "onSuccess: testing ends");
                    }
                    catch (Throwable ex) {
                        // tell the upstream we can't accept any more data (OPTIONAL)
                        dispose();
                        // pass error to error handler
                        onError(ex);
                    }
                }

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

Good luck :)

Upvotes: 1

nsndvd
nsndvd

Reputation: 830

onError is for errors that happen along the operator chain. What you do in onSuccess is already at the end of it, and will not be reported in onError.

Upvotes: 0

Related Questions