简体   繁体   English

使用RxJava2和Retrofit2 Mosby MVI的OnErrorNotImplementedException

[英]OnErrorNotImplementedException using RxJava2 and Retrofit2 Mosby MVI

I'm getting a OnErrorNotImplementedException thrown and the app crashes, despite handling the error downstream(?). 我得到一个OnErrorNotImplementedException抛出并且应用程序崩溃,尽管处理下游错误(?)。

Exception 例外

E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-1
Process: pl.netlandgroup.smartsab, PID: 9920
io.reactivex.exceptions.OnErrorNotImplementedException: HTTP 401 Unauthorized
    at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)
    at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)
    at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:74)
    at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:119)
    at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:119)
    at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onError(ObservableSubscribeOn.java:63)
    at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:56)
    at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:37)
    at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:43)
    at io.reactivex.Observable.subscribe(Observable.java:10838)
    at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
    at io.reactivex.Observable.subscribe(Observable.java:10838)
    at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
    at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:452)
    at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
    at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)
 Caused by: retrofit2.adapter.rxjava2.HttpException: HTTP 401 Unauthorized
    at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:54)
    at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:37) 
    at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:43) 
    at io.reactivex.Observable.subscribe(Observable.java:10838) 
    at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34) 
    at io.reactivex.Observable.subscribe(Observable.java:10838) 
    at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96) 
    at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:452) 
    at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61) 
    at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
    at java.lang.Thread.run(Thread.java:761) 

Retrofit Repository: 改造仓库:

class RetrofitRepository (retrofit: Retrofit) {

    val apiService: ApiService = retrofit.create(ApiService::class.java)
    var size: Int = 0

    fun getMapResponse(pageIndex: Int = 0): Observable<MapResponse> {
        return apiService.getMapResponse(pageIndex = pageIndex)
                .doOnError { Log.d("error", it.message) }
                .doOnNext { Log.d("currThread", Thread.currentThread().name) }

    }

    fun getItemsFormResponses(): Observable<List<Item>> {
        val list = mutableListOf<Observable<List<Item>>>()
        val resp0 = getMapResponse()
        resp0.subscribe { size = it.totalCount }
        var accum = 0
        do {
            list.add(getMapResponse(accum).map { it.items })
            accum++
        } while (list.size*200 < size)
        return Observable.merge(list)
    }
}

This results are observed by Interactor: Interactor观察到这一结果:

class MapInteractor @Inject constructor(private val repository: RetrofitRepository) {

    fun getMapItems(): Observable<MapViewState> {
        return repository.getItemsFormResponses()
                .map {
                    if(it.isEmpty()) {
                        return@map MapViewState.EmptyResult()
                    } else {
                        val mapItems = it.map { it.toMapItem() }
                        return@map MapViewState.MapResult(mapItems)
                    }
                }
                .doOnNext { Log.d("currThread", Thread.currentThread().name) }
                .startWith(MapViewState.Loading())
                .onErrorReturn { MapViewState.Error(it) }
    }
}

The onErrorReturn { MapViewState.Error(it) } emits correctly (right before the app crash I can see the correct thing rendered on screen). onErrorReturn { MapViewState.Error(it) }正确发出(在应用程序崩溃之前,我可以看到屏幕上呈现的正确内容)。 How can I avoid this exception while still maintaining the MVI architecture? 如何在保持MVI架构的同时避免此异常?

EDIT 编辑

The answer provided by dimsuz was the correct solution, although to achieve the merging and returning one Observable with all items it had to be modified to this: dimsuz提供的答案是正确的解决方案,虽然为了实现合并并返回一个Observable,所有项目都必须修改为:

fun getMapItems(): Observable<List<Item>> {
    return getMapResponse().map {
        val size = it.totalCount
        val list = mutableListOf<Observable<List<Item>>>()
        var accum = 0
        do {
            list.add(getMapResponse(accum++).map { it.items })
        } while (list.size*200 < size)
        return@map list.zip { it.flatten() }
    }.mergeAll()
}

I believe the error is thrown in getItemsFromResponse() along the lines of: 我相信错误是在getItemsFromResponse()引发的:

    val resp0 = getMapResponse()
    resp0.subscribe { size = it.totalCount }

Here you subscribe, but do not handle the error case. 在这里您订阅,但不处理错误情况。 Actually this code is incorrect, because you break the Rx chain in two independent pieces, you shouldn't do that. 实际上这段代码是不正确的,因为你在两个独立的部分中打破了Rx链,你不应该这样做。

What you should do is something like this: 你应该做的是这样的事情:

fun getItemsFormResponses(): Observable<List<Item>> {
  return getMapResponse().map { resp0 ->
    val size = resp0.totalCount

    val list = mutableListOf<Observable<List<Item>>>()
    var accum = 0
    do {
      list.add(getMapResponse(accum).map { it.items })
      accum++
    } while (list.size*200 < size)
    return Observable.merge(list)
  }
}

Ie extract size by extending the chain with an operator, rather then breaking it with subscribe() . 即通过使用运算符扩展链来提取size ,而不是使用subscribe()将其拆分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM