RxJava:吞没错误后,上游永远不会完成

时间:2018-10-02 23:51:06

标签: android kotlin rx-java rx-java2

我正在使用RxJava遍历文件列表,进行网络调用以上传每个文件,然后将成功上传的文件收集到列表中,并在成功后将这些文件持久保存在订阅服务器中。

此代码有效,但发生错误时除外。行为应该是它记录错误并继续执行,除非发生错误,否则订户的onSuccess lambda永远不会被调用。

观察者是否期望发出与原始可迭代元素相同数量的元素?迭代完所有项目后,如何跳过错误并完成错误?除了Single.never()之外,还有其他东西可以完成不将错误转发到下游吗?

queryFiles()?.let { files ->
    Observable.fromIterable(files)
            .flatMapSingle { file ->
                uploadFile(file)
                        .onErrorResumeNext { error ->
                            log(error)
                            Single.never() // if this is returned onSuccess is never called
                        }
                        .map { response ->
                            file.id = response.id
                            file
                        }
            }
            .toList()
            .subscribe( { uploadedFiles ->
                persist(uploadedFiles) // if error occurs above, this is never called
            }, { error ->
                log(error)
            })
}

2 个答案:

答案 0 :(得分:2)

您的问题是Single只能产生两个值,即成功结果或失败结果。通过先将故障转换为Maybe,然后使用基本上相同的代码来处理故障和成功,可以将故障转变为“忽略”状态。

Maybe.onErrorResumeNext的返回值为Maybe.empty()会导致0或1个结果,而Maybe.map仅在有值的情况下执行,可以按照您所描述的那样准确地解决问题。

自适应代码:

        .flatMapMaybe { file ->
            uploadFile(file).toMaybe()
                    .onErrorResumeNext { error: Throwable ->
                        log(error)
                        Maybe.empty()
                    }
                    .map { response ->
                        file.id = response.id
                        file
                    }
        }

答案 1 :(得分:0)

这是我过去使用zip方法处理它的方式。

  // create an observable list that you can process for you file uploads
  val responses: Response = listOf<Response>()

  queryFiles()?.let { file ->

    val observable = Observable.create(ObservableOnSubscribe<Response> { emitter ->
      // you can modify this section to your data types
      try {
        // with your uploadFile method you might be able to just add them
        // all the responses list
        emitter.onNext(uploadFile(file))
        emitter.onComplete()
      } catch (e: Exception) {
        emitter.onError(e)
      }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
    responses.add(observable)    
  }

  // i setup a simple booleanArray to handle success/failure but you can add
  // all the files that fail to a list and use that later    
  val isSuccessful = booleanArrayOf(true)
  Observable.zip<Response, Boolean>(responses, Function<Array<Any>, Boolean> { responses ->
    var isSuccessful: Boolean? = java.lang.Boolean.TRUE
    // handle success or failure
    isSuccessful
  }).subscribe(Consumer<Boolean> { aBoolean -> isSuccessful[0] = aBoolean!! }, Consumer<Throwable> { throwable ->
    isSuccessful[0] = false
  }, Action {
    // handle your OnComplete here
    // I would check the isSuccessful[0] and handle the success or failure        
  })

这会将您所有的上传内容创建到可观察的列表中,可以使用zip方法进行处理和合并。当它们完成任何操作后,这会将它们全部合并为一个数组,以便您可以对它们进行循环-您的结果来自uploadFile()方法。本示例从返回的响应中检查成功或失败。我删除了注释// handle success or failure所在的大多数逻辑。在函数方法中,您可以跟踪失败或成功的文件上传。