【问题标题】:java.net.SocketException: Socket closed not caught by RxJava onError (Single)java.net.SocketException:RxJava onError 未捕获的套接字已关闭(单)
【发布时间】:2020-10-11 21:50:45
【问题描述】:

我正在做这样的事情:在我的Fragment 中,我观察到由ViewModel 暴露的LiveData,该ViewModel 封装了不同的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,但似乎我没有在doSomething()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

我知道在官方 Retrofit 存储库中打开了一个类似的 issue 和一个类似的 SO 问题 here,但是这两个尚未解决,因此我想知道这里是否有人遇到过相同的行为。

【问题讨论】:

  • 您检查了互联网连接吗?已声明互联网许可?
  • 你检查过邮递员或任何api客户端的api吗?
  • @Quicklearner 我拥有必要的权限和有效的互联网连接。另外,抱歉,您链接的答案与我的问题无关。
  • @Quicklearner 你读过我的问题吗?如果您真的理解我的问题,您会意识到我的问题无法通过简单的 Postman 检查来解决。
  • @Quicklearner 在出现更多不相关的 cmets 之前,请注意此错误不是由 Internet 连接或缺少权限引起的。这是由 此应用程序 关闭套接字然后继续使用它引起的。它表明某处代码中存在错误。

标签: java android retrofit2 rx-java2


【解决方案1】:

我发现了问题所在。首先,我实现了一个“不活动计时器”,它将所有屏幕(我使用Fragments 用于屏幕)返回到我的应用程序的第一个/主屏幕。因此,假设计时器的值设置为 30 秒,如果没有与 UI 交互并且计时器达到 30 秒,那么我的应用程序将返回主屏幕。

其次,我启动请求的ViewModelFragment 相关联,因为它实现了DefaultLifecycleObserver,这意味着它将接收LifecycleOwner 更改/回调,只要我称之为:getViewLifecycleOwner().getLifecycle().addObserver(viewModel)在我的Fragment#onViewCreated。然后我覆盖ViewModel 中的onStop(@NonNull LifecycleOwner owner) 并调用compositeDisposable.clear(),这意味着一旦Fragment 我的ViewModel 绑定到接收onStop,我想取消我使用RxJava2 发出的所有未决API 请求。

最后一条信息是我的OkHttp 客户端的超时值大于不活动计时器的值,因此不活动计时器会突然导致我的请求 API 在完成之前被取消。

总而言之,会发生以下情况:当不活动计时器到时,请求 API FragmentonStop 会在屏幕变回主屏幕时被调用,然后 ViewModel 会调用 @987654338 @ 处理当前的 RxJava 一次性,因此我无法在 onError 上接收任何内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-25
    • 2011-09-04
    • 2014-10-07
    • 2014-09-09
    • 2020-11-16
    • 1970-01-01
    • 2014-03-01
    相关资源
    最近更新 更多