java.net.SocketException: 套接字关闭未被 RxJava onError 捕获(单)
java.net.SocketException: Socket closed not caught by RxJava onError (Single)
我正在做这样的事情:在我的 Fragment
中,我正在观察 ViewModel
暴露的 LiveData
,它封装了不同的 UI 状态,例如错误、加载,成功状态等。在上述 ViewModel
中,我启动了一个 RxJava2 流,该流通过 Retrofit 启动了一系列 REST API 请求:
public LiveData<UIState> doSomething() {
compositeDisposable.add(somethingRepo.doA()
.andThen(somethingRepo.doB())
.andThen(somethingRepo.doC())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(disposable -> status.setValue(UIState.LOADING()))
.subscribe(() -> status.setValue(UIState.SUCCESS()), error -> {
Log.d("SettingsVM", "error: " + error.getClass().getSimpleName());
if(error instanceof VersionAlreadyExistsException) {
status.setValue(UIState.VERSION_EXISTS());
} else {
status.setValue(UIState.ERROR(error.getMessage()));
}
})
);
return status;
}
但是,根据我实现 HttpLoggingInterceptor.Logger
的自定义记录器,我在 somethingRepo.doA()
期间收到 java.net.SocketException: Socket closed
,但似乎我没有在 [=21] 收到异常=] 的 onError
。这是完整的 somethingRepo.doA()
:
public Completable doA() {
return api.doRequest(paramRepository.getUrl(false),
paramRepository.getAuthorization(),
paramRepository.getName())
.flatMapCompletable(requestResponse-> {
if(paramRepository.getVersion().contentEquals(requestResponse.getVersion())) {
return Completable.error(new VersionAlreadyExistsException());
} else {
return Completable.complete();
}
});
}
api.doRequest 是一个 GET
请求,如下所示:
@GET
Single<RequestResponse> doRequest (
@Url String url,
@Header("authorization") String authorization,
@Query("merch") String name);
有趣的是,在另一个 Android 应用程序上,我将 POST
发送到我在上一个示例中使用的同一个 URL,而我得到的是 HTTP FAILED: java.net.ConnectException: Failed to connect to /180.232.98.122:7443
。
我知道一个类似的 issue being opened in the official Retrofit repo and a similar SO question here,但这两个问题尚未解决,因此我想听听这里是否有人遇到过相同的行为。
我明白问题出在哪里了。首先,我实现了一个“不活动计时器”,returns 所有屏幕(我对屏幕使用 Fragments
)到我应用程序中的 first/home 屏幕。因此,假设为计时器设置了 30 秒的值,如果没有与 UI 的交互发生并且计时器达到 30 秒,那么我的应用程序将返回主屏幕。
其次,我开始请求的 ViewModel
与 Fragment
相关联,因为它实现了 DefaultLifecycleObserver
,这意味着它将接收 LifecycleOwner
changes/callbacks,前提是我在 Fragment#onViewCreated
中这样称呼:getViewLifecycleOwner().getLifecycle().addObserver(viewModel)
。然后我在 ViewModel
中覆盖 onStop(@NonNull LifecycleOwner owner)
并调用 compositeDisposable.clear()
,这意味着我想取消所有未决的 API 请求,一旦 Fragment
我使用 RxJava2 发出我的 ViewModel
绑定到接收 onStop
.
最后一条信息是我的 OkHttp
客户端的超时值大于不活动计时器值,因此不活动计时器突然导致我的请求 API 在它之前被取消完成。
总而言之,会发生以下情况:当不活动计时器计时结束时,请求 API Fragment
的 onStop
在屏幕变回主屏幕时被调用,然后 ViewModel
调用 compositeDisposable.clear()
处理当前的 RxJava 一次性,因此我无法在 onError
.
上收到任何东西
我正在做这样的事情:在我的 Fragment
中,我正在观察 ViewModel
暴露的 LiveData
,它封装了不同的 UI 状态,例如错误、加载,成功状态等。在上述 ViewModel
中,我启动了一个 RxJava2 流,该流通过 Retrofit 启动了一系列 REST API 请求:
public LiveData<UIState> doSomething() {
compositeDisposable.add(somethingRepo.doA()
.andThen(somethingRepo.doB())
.andThen(somethingRepo.doC())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(disposable -> status.setValue(UIState.LOADING()))
.subscribe(() -> status.setValue(UIState.SUCCESS()), error -> {
Log.d("SettingsVM", "error: " + error.getClass().getSimpleName());
if(error instanceof VersionAlreadyExistsException) {
status.setValue(UIState.VERSION_EXISTS());
} else {
status.setValue(UIState.ERROR(error.getMessage()));
}
})
);
return status;
}
但是,根据我实现 HttpLoggingInterceptor.Logger
的自定义记录器,我在 somethingRepo.doA()
期间收到 java.net.SocketException: Socket closed
,但似乎我没有在 [=21] 收到异常=] 的 onError
。这是完整的 somethingRepo.doA()
:
public Completable doA() {
return api.doRequest(paramRepository.getUrl(false),
paramRepository.getAuthorization(),
paramRepository.getName())
.flatMapCompletable(requestResponse-> {
if(paramRepository.getVersion().contentEquals(requestResponse.getVersion())) {
return Completable.error(new VersionAlreadyExistsException());
} else {
return Completable.complete();
}
});
}
api.doRequest 是一个 GET
请求,如下所示:
@GET
Single<RequestResponse> doRequest (
@Url String url,
@Header("authorization") String authorization,
@Query("merch") String name);
有趣的是,在另一个 Android 应用程序上,我将 POST
发送到我在上一个示例中使用的同一个 URL,而我得到的是 HTTP FAILED: java.net.ConnectException: Failed to connect to /180.232.98.122:7443
。
我知道一个类似的 issue being opened in the official Retrofit repo and a similar SO question here,但这两个问题尚未解决,因此我想听听这里是否有人遇到过相同的行为。
我明白问题出在哪里了。首先,我实现了一个“不活动计时器”,returns 所有屏幕(我对屏幕使用 Fragments
)到我应用程序中的 first/home 屏幕。因此,假设为计时器设置了 30 秒的值,如果没有与 UI 的交互发生并且计时器达到 30 秒,那么我的应用程序将返回主屏幕。
其次,我开始请求的 ViewModel
与 Fragment
相关联,因为它实现了 DefaultLifecycleObserver
,这意味着它将接收 LifecycleOwner
changes/callbacks,前提是我在 Fragment#onViewCreated
中这样称呼:getViewLifecycleOwner().getLifecycle().addObserver(viewModel)
。然后我在 ViewModel
中覆盖 onStop(@NonNull LifecycleOwner owner)
并调用 compositeDisposable.clear()
,这意味着我想取消所有未决的 API 请求,一旦 Fragment
我使用 RxJava2 发出我的 ViewModel
绑定到接收 onStop
.
最后一条信息是我的 OkHttp
客户端的超时值大于不活动计时器值,因此不活动计时器突然导致我的请求 API 在它之前被取消完成。
总而言之,会发生以下情况:当不活动计时器计时结束时,请求 API Fragment
的 onStop
在屏幕变回主屏幕时被调用,然后 ViewModel
调用 compositeDisposable.clear()
处理当前的 RxJava 一次性,因此我无法在 onError
.