Getting error "Callable returned null" when using RxJava2
Asked Answered
I

6

17

I am using RxJava2 in my android project.

I am using the following code to create the Observable

public Observable<AlbumDetails> loadAlbumFromAlbumId(final String albumId) {
    return Observable.fromCallable(new Callable<AlbumDetails>() {
        @Override
        public AlbumDetails call() throws Exception {
             AlbumDetails albumDetails = getAlbumDetails(albumId);     
             return albumDetails;   
       });
}

From the observable, I am getting following error in the onError method of DisposableObserver

Callable returned null

This didn't use to happend when using RxJava.

Inquiline answered 3/5, 2017 at 17:59 Comment(1)
not giving an error at compilation time neither in debug apk but give you a shot at released apk.Munro
M
21

I used to have code like this:

Observable<R> obs = Observable.fromCallable(this::work);

work() may return null and as you noted, RxJava 2 is not happy with this.

Method 1

Observable<R> obs = Maybe.fromCallable(this::work).toObservable();

In this way, the end consumer - the observer - will only kick off if work() had anything to return. If work() returned null then it's the same as subscribing to an empty Observer; nothing happens.

Method 2

Observable<R> obs = Observable.create(e -> {
    R r = work();

    if (r != null) {
        e.onNext(r);
    }

    e.onComplete();
});

Method 3:

Wrapping each emission in an Optional = bad idea for a number of reasons.

Mainly because I only use Optional in my APIs if it is expected and sort of the "normal" scenario that you get a null every now and then. If null is not expected or very rare, maybe as a direct result of another API call done by the same consumer, then I return null and let the consumer deal with it in these exceptional cases rather than having every consumer deal with Optional all over the place.

Mayberry answered 25/10, 2018 at 11:23 Comment(0)
I
9

As given here in the wiki :

What's Different in 2.0

RxJava 2.x no longer accepts null values. Having null as a stream element causes a NullPointerException immediately and thus the onError method is called.

This has been done mainly to avoid crashes due to NullPointerException in the apps.

I solved this by a rather simple approach. I checked if the value was null, and if it was, I replaced the null with a placeholder object.

Other more sophisticated approaches also exist that tackle this issue, but for my use case, this simple approach was enough.

Inquiline answered 3/5, 2017 at 17:59 Comment(0)
A
3

RxJava 2.x no longer accepts null values without implementing error handler

example

Observable.fromCallable(() -> null)
    .subscribe(System.out::println, Throwable::printStackTrace);

Observable.just(1).map(v -> null)
    .subscribe(System.out::println, Throwable::printStackTrace);

Solution for your questian

When you call/subscribe this method do like bellow

Observable<AlbumDetails> testObservable= Observable.create(emitter -> { ... });
testObservable.subscribe(t -> System.out.print(t),Throwable::printStackTrace);
Aggress answered 9/11, 2017 at 14:19 Comment(0)
J
2

Assuming that getAlbumDetails(albumId) method returns null in case of the data is not available or error, and you are willing to just gracefully complete your stream in such situation, you could use something like this:

public Observable<AlbumDetails> loadAlbumFromAlbumId(String albumId) {
    return Maybe.fromCallable(() -> getAlbumDetails(albumId))
        .onErrorComplete()
        .toObservable();
};

I've replaced the anonymous class with lambda for better readability, but you can keep it as is, of course.

Jacobine answered 27/10, 2018 at 14:1 Comment(0)
H
0

You can also wrap the return value in an Optional (Java 8). And the map that within your subscription using optional.isPresent() and optional.get().

Handed answered 9/4, 2018 at 21:5 Comment(0)
E
0

I came up with this workaround :

First created a wrapper class:

class NullableObject<T>(val value: T?)

Then created an extension function for Single like this:

inline fun <T> runInSingle(
        crossinline block: () -> T,
        crossinline callback: (T?) -> Unit,
        crossinline onError: (Throwable) -> Unit) {

   Single.fromCallable {
      return@fromCallable block().toNullableObject()
   }.subscribeOn(Schedulers.io())
           .observeOn(AndroidSchedulers.mainThread())
           .subscribe { result, error ->
              if (error != null) {
                 onError(error)
              } else {
                 callback(result.value)
              }
           }
}

fun <T> T.toNullableObject(): NullableObject<T> = NullableObject(this)

How to use :

runInSingle({
         doSomethingInBackgroundWhichMayReturnNull()
      }, { result ->
         if(result != null) {
           doSomethingWithTheNonNullResult()
         } else {
           doSomethingWithTheNullResult()
         }
      }, { error ->
         error.printStackTrace()
      })
Epizootic answered 18/2, 2021 at 15:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.