Mosius
Mosius

Reputation: 1682

RxJava - Subscribe doesn't catch exception which cause crash

I am trying to subscribe to a SingleSource, I have implemented both onSuccess And onError of subscribe method, here is my code:

disposable.add(repository
                .getUser1()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    toast(it)
                }, {
                    toast(it.message ?: "Error")
                }))

The Problem is When an exception occur in repository it does't being caught in onError

Here is my repository implementation:

class Repository(private val sp: SharedPreferences) {

    // It crashes
    fun getUser1(): Single<String> = generateUser(name, "Hello")

    // it doesn't crash
    fun getUser2(): Single<String> = Single.fromCallable { name }.flatMap { generateUser(it, "Hello") }

    private var name: String
        get() = sp.getString("user", null) ?: throw NoNameException()
        set(value) = sp.edit().putString("user", value).apply()

    private fun generateUser(name: String, message: String): Single<String> = Single.just("$message $name")

}

And here is the crash Log:

09-24 10:13:40.930 6934-6934/com.mosius.samplerxtest E/AndroidRuntime: FATAL EXCEPTION: main Process: com.mosius.samplerxtest, PID: 6934 java.lang.RuntimeException: java.lang.reflect.InvocationTargetException at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)  Caused by: com.mosius.samplerxtest.NoNameException: No Name Supplied at com.mosius.samplerxtest.Repository.getName(Repository.kt:17) at com.mosius.samplerxtest.Repository.getUser1(Repository.kt:10) at com.mosius.samplerxtest.MainActivity$onCreate$1.onClick(MainActivity.kt:24) at android.view.View.performClick(View.java:6597) at android.view.View.performClickInternal(View.java:6574) at android.view.View.access$3100(View.java:778) at android.view.View$PerformClick.run(View.java:25881) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6649) at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)

What's the different between these two implementation?

Upvotes: 0

Views: 930

Answers (1)

Mosius
Mosius

Reputation: 1682

In the getUser1() method, SingleSource has not been created yet, so it is out of Rx control to handle the exception.

In the Second one the name is being fetched in Rx scope therefore it could handle the exception

Upvotes: 1

Related Questions