1

I have been trying for quite some time but I am unable to wrap my head around processing null values in RxJava & Kotlin

I have a Room database which returns a list of some entities (topics) from database. I need to pick one random item from the list or process different action if the list is empty.

After reading through various answers on SO and trying different approaches. I tried using Optional:

fun getRandomTopic(): Single<Optional<Topic>> {
        return topicDao.getAll().flatMap { topics ->
            if (topics.isEmpty()) {
                Single.just(Optional.ofNullable(null))
            }

            val index = (Math.random() * topics.size).toInt()
            Single.just(Optional.of(topics[index]))
        }
    }

This function is observed in my activity:

viewModel.getRandomTopic()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { result ->
                    if (result.isPresent) {
                        viewModel.currentTopic.postValue(result.get())
                    } else {
                        Toast.makeText(this, "No topic found", Toast.LENGTH_SHORT).show()
                    }
                })

However, this always triggers either null pointer exception or IndexOutOfBoundsException:

io.reactivex.exceptions.OnErrorNotImplementedException: Index: 0, Size: 0
        at io.reactivex.internal.functions.Functions$14.accept(Functions.java:229)
        at io.reactivex.internal.functions.Functions$14.accept(Functions.java:226)
        at io.reactivex.internal.observers.ConsumerSingleObserver.onError(ConsumerSingleObserver.java:44)
        at io.reactivex.internal.operators.single.SingleObserveOn$ObserveOnSingleObserver.run(SingleObserveOn.java:79)
        at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:111)
        at android.os.Handler.handleCallback(Handler.java:761)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:156)
        at android.app.ActivityThread.main(ActivityThread.java:6523)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
     Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
        at java.util.ArrayList.get(ArrayList.java:411)
        at cz.xxx.TopicViewModel$getRandomTopic$1.apply(TopicViewModel.kt:31)
        at cz.xxx.TopicViewModel$getRandomTopic$1.apply(TopicViewModel.kt:17)

It seems that the condition

if (topics.isEmpty()) {
       Single.just(Optional.ofNullable(null))
}

is somehow ignored and the statement continues even when the array is empty. What am I doing wrong here?

1 Answer 1

3

You have basically described where problem is. If you take a look at source code in Android Studio, expression Single.just(Optional.ofNullable(null)) is not evaluated as return value of the .flatMap().

AS screenshot

Only last value of an lambda is. I recommend you to write down return statements like return@something to make a code more clear and understandable. Solution?

fun getRandomTopic(): Single<Optional<Topic>> {
    return topicDao.getAll().flatMap { topics ->
        return@flatMap if (topics.isEmpty()) {
            Single.just(Optional.ofNullable<Topic>(null))
        } else {
            val index = (Math.random() * topics.size).toInt()
            Single.just(Optional.of(topics[index]))
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, just noticed that the if was ignored because wrong type inference.
Call requires API level 24: java.util.Optional#ofNullable

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.