在RXjava2中调用ObservableEmitter的onError时出现UndeliverableException

时间:2017-05-10 06:10:41

标签: retrofit2 rx-android rx-java2

我有一个创建类似下面的发射器的方法,在改装回调中调用onError会出现问题(可能是正常行为)。尝试调用onError时,我得到了UndeliverableException。

我可以通过检查subscriber.isDiposed()来解决这个问题,我想知道如何调用onError coz我需要通知我的UI级别。

  
    
        
  • 加法1
  •     
  
--> RxJava2CallAdapterFactoryalready implemented   
private static Retrofit.Builder builderSwift = new Retrofit.Builder()
           .baseUrl(URL_SWIFT)
           .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
           .addConverterFactory(GsonConverterFactory.create())
           .addConverterFactory(new ToStringConverterFactory());

--> When i added below code to application class app won't crash
--> but i get java.lang.exception instead of my custom exception  

RxJavaPlugins.setErrorHandler(Functions<Throwable>emptyConsumer());

@Override
    public void onFileUploadError(Throwable e) {
        Log.d(TAG, "onFileUploadError: " + e.getMessage());
    }
public Observable<UploadResponseBean> upload(final UploadRequestBean uploadRequestBean, final File file) {
    return Observable.create(new ObservableOnSubscribe<UploadResponseBean>() {
        @Override
        public void subscribe(@NonNull final ObservableEmitter<UploadResponseBean> subscriber) throws Exception {

                 // ---> There are no problem with subscriber while calling onError        

                // ---> Retrofit2 service request 
                ftsService.upload(token, uploadRequestBean, body).enqueue(new Callback<UploadResponseBean>() {
                    @Override
                    public void onResponse(Call<UploadResponseBean> call, Response<UploadResponseBean> response) {

                        if (response.code() == 200){
                            // --->  calling onNext works properly
                            subscriber.onNext(new UploadResponseBean(response.body().getUrl()));
                        }
                        else{
                            // --->  calling onError throws UndeliverableException
                            subscriber.onError(new NetworkConnectionException(response.message()));                
                        }
                    }

                    @Override
                    public void onFailure(Call call, Throwable t) {
                        subscriber.onError(new NetworkConnectionException(t.getMessage()));
                    }
                });
        }
    });
}

3 个答案:

答案 0 :(得分:8)

由于版本2.1.1 func (c App) Index() revel.Result { dat := c.Params.Get(sendIt); return c.Render(dat) } 可用:

  

现在发射器API(例如FlowableEmitter,SingleEmitter等)   提供了一个新方法tryOnError尝试发出Throwable if   序列未被取消/处置。与常规onError不同,if   下游不再愿意接受事件,方法   返回false并且没有发出UndeliverableException信号。

https://github.com/ReactiveX/RxJava/blob/2.x/CHANGES.md

答案 1 :(得分:7)

问题就像你说你需要检查Subscriber是否已经处理掉了,因为RxJava2对Subscriber已经处理过后引发的错误更加严格。
RxJava2将此类错误传递给RxJavaPlugins.onError,默认情况下打印到堆栈跟踪并调用线程未捕获的异常处理程序。你可以阅读完整的解释here

现在发生的事情是,您可能在查询完成并发送错误之前从此Observable取消订阅(处置),因此您获得了UndeliverableException

  

我想知道如何调用onError coz我需要通知我的UI级别。

因为这是在你的用户界面取消订阅后发生的,所以用户界面不应该关心。在正常流程中,这个错误应该正确传递。

关于您的实施的一些一般性观点:

  • 如果您之前已取消订阅,onError也会出现同样的问题。
  • 此处没有取消逻辑(导致此问题的原因),即使Subscriber取消订阅,请求仍会继续。
  • 即使您实施此逻辑(使用ObservableEmitter.setCancellable() / setDisposable()),如果您在请求完成之前取消订阅,您仍会遇到此问题 - 这将导致取消和您的{ {1}}逻辑将调用onFailure,同样的问题也会发生。
  • 当您通过Retrofit执行异步调用时,指定的订阅onError()将不会使Scheduler线程上的实际请求发生,而只会发生订阅。您可以使用Scheduler和Retrofit阻止调用Observable.fromCallable来获得对实际发生的线程调用的更多控制。

总结一下 - 在这种情况下,使用execute保护onError()的来电是一种很好的做法 但我认为最好的做法是使用Retrofit RxJava调用适配器,这样你就可以进行改造调用ObservableEmitter.isDiposed(),并且已经考虑了所有这些因素。

答案 2 :(得分:0)

我发现此问题是由在Fragment中检索视图模型时使用不正确的上下文引起的:

ViewModelProviders.of(requireActivity(), myViewModelFactory).get(MyViewModel.class);

因此,视图模型位于活动的上下文中,而不是片段。将其更改为以下代码可解决此问题。

ViewModelProviders.of(this, myViewModelFactory).get(MyViewModel.class);