Search code examples
mvvmkotlinrx-java2reactivex

Reactivex NetworkOnMainThreadException even when subcribed


I'm trying to build an MVVM Kotlin app that uses Reactivex to make the Async calls to the API.

I've seen alot of threads with the same problem but on all of them the OP forgot to put the subscribeOn in the call, in my code i do this and still have the network error. I've looked in the debugger to find the problem but to no succes.

class NoteViewModel(apiKey : String) : ViewModel () { // , Observable {
private lateinit var noteAdapter : NoteAdapter

private val notesList = MutableLiveData <ArrayList<Note>>()
private var subscription : Disposable
private val noteCollector = NoteCollector()
private val isLoading = MutableLiveData<Boolean>()

init {
    subscription = noteCollector.getAll(apiKey)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe { onCollectNotesStart() }
            .doOnTerminate { onCollectNotesFinished() }
            .subscribe(
                    { result -> onCollectNotesSuccess(result) },
                    { error -> onCollectNotesError(error) }
            )
}
...
}

If you need more info let me know, i'll provide it.

EDIT: added stacktrace

E/AndroidRuntime: FATAL EXCEPTION: main
Process: jari.student.hogent.cominghome, PID: 2532
java.lang.RuntimeException: Unable to start activity ComponentInfo{jari.student.hogent.cominghome/jari.student.hogent.cominghome.Activities.MainActivity}: android.os.NetworkOnMainThreadException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2955)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6938)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
 Caused by: android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1448)
    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:102)
    at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
    at java.net.InetAddress.getAllByName(InetAddress.java:787)
    at com.android.okhttp.Dns$1.lookup(Dns.java:39)
    at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:200)
    at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:148)
    at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:90)
    at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:190)
    at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:142)
    at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:104)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:410)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:343)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:489)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262)
    at com.github.kittinunf.fuel.toolbox.HttpClient.setBodyIfDoOutput(HttpClient.kt:91)
    at com.github.kittinunf.fuel.toolbox.HttpClient.executeRequest(HttpClient.kt:39)
    at com.github.kittinunf.fuel.core.requests.TaskRequest.call(TaskRequest.kt:14)
    at com.github.kittinunf.fuel.core.DeserializableKt$response$result$1.invoke(Deserializable.kt:81)
    at com.github.kittinunf.fuel.core.DeserializableKt$response$result$1.invoke(Unknown Source:0)
    at com.github.kittinunf.result.Result$Companion.of(Result.kt:116)
    at com.github.kittinunf.fuel.core.DeserializableKt.response(Deserializable.kt:81)
    at com.github.kittinunf.fuel.core.Request.responseObject(Request.kt:344)
    at jari.student.hogent.cominghome.Models.NoteCollector.getAll(NoteCollector.kt:22)
    at jari.student.hogent.cominghome.ViewModels.NoteViewModel.<init>(NoteViewModel.kt:22)
    at jari.student.hogent.cominghome.ViewModels.CustomViewModelFactory.create(CustomViewModelFactory.kt:11)
    at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:134)
    at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:102)
    at jari.student.hogent.cominghome.Fragments.NoteFragment.onCreateView(NoteFragment.kt:27)
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
    at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
    at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
    at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
E/AndroidRuntime:     at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
    at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
    at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
    at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
    at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
    at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
    at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1340)
    at android.app.Activity.performStart(Activity.java:7200)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2918)
        ... 9 more

EDIT 2: added getAll methode

override fun getAll(ApiKey: String): Observable<ArrayList<Note>> {
    val bodyJson: JSONObject = JSONObject()
            .put("apiKey", ApiKey)

    val notesList: ArrayList<Note> = ArrayList()

    val (_, _, result) = path.httpPost()
            .header(mapOf("Content-Type" to "application/json"))
            .body(bodyJson.toString())
            .responseObject(Note.Deserializer())
    val (notes, err) = result
    if (err != null){
        throw err.exception
    }
    notes?.forEach { note ->
        notesList.add(note)
    }

    return Observable.fromArray(notesList)
}

Solution

  • Please change your getAll implementation to this:

    override fun getAll(ApiKey: String): Observable<ArrayList<Note>> 
        = Observable.create { emitter -> 
            val bodyJson: JSONObject = JSONObject()
                    .put("apiKey", ApiKey)
    
            val notesList: ArrayList<Note> = ArrayList()
    
            val (_, _, result) = path.httpPost()
                    .header(mapOf("Content-Type" to "application/json"))
                    .body(bodyJson.toString())
                    .responseObject(Note.Deserializer())
            val (notes, err) = result
            if (err != null) {
                throw err.exception
            }
            notes?.forEach { note ->
                notesList.add(note)
            }
            emitter.onNext(notesList)
        }