【问题标题】:Poll second URL until JSON returns an expected parameter轮询第二个 URL,直到 JSON 返回预期的参数
【发布时间】:2018-04-10 21:38:10
【问题描述】:

我正在使用一个旅行 API,我首先发出创建会话的请求,然后使用从该 URL 返回的会话 URL 进行调用,直到其状态参数返回 UpdatesComplete

这是我目前所拥有的:

lateinit var pollUrl: String
travelInteractor.createSession("LHR", "AKL", "2018-04-20", "2018-04-22")
.doOnSubscribe {
    loading.postValue(true)
}
.flatMap { url ->
    pollUrl = url
    travelInteractor.pollResults(pollUrl)
    .retryWhen {
        it.delay(1000, TimeUnit.MILLISECONDS)
    }
}
.doOnNext {
    if (it.status != "UpdatesComplete") travelInteractor.pollResults(pollUrl)
         .retryWhen {
             it.delay(1000, TimeUnit.MILLISECONDS)
         }
}
.subscribe({
     // Subscription stuff
)}

目前发生的情况是它将调用doOnNext(),然后它会进行网络投票,但我不会捕获订阅,也不会链接另一个投票。有没有更有效的方法可以写这个?


解决方案

感谢iagreen 我设法通过以下方式实现了这一目标:

lateinit var pollUrl: String
travelInteractor.createSession("LHR", "AKL", "2018-04-20", "2018-04-22")
.doOnSubscribe {
    loading.postValue(true)
}
.flatMap { url ->
    travelInteractor.pollResults(url)
    .retryWhen {
        it.delay(1000, TimeUnit.MILLISECONDS)
    }
    .repeatWhen {
        it.delay(1000, TimeUnit.MILLISECONDS)
    }
    .filter {
        it.itineraries.map { ... } // Use response here appropriately and then check status
        it.status == "UpdatesComplete"
    }
    .take(1)
}
.subscribe({
     // Subscription stuff
)}

【问题讨论】:

    标签: android kotlin rx-java2


    【解决方案1】:

    我假设您的 pollResults(url) 方法返回一个 SingleObservable,其行为类似于一个单一的 - 它返回一个结果,然后返回 onComplete。如果确实如此,您可以使用repeatWhen 重试成功的请求,使用retryWhen 重试错误。请参阅下面的代码。

    skyScannerInteractor.createSession("LHR", "AKL", "2018-04-20", "2018-04-22")
        .doOnSubscribe {
            loading.postValue(true)
        }
        .flatMap { url ->
            skyScannerInteractor.pollResults(url)
                .repeatWhen { complete -> complete.delay(1, TimeUnit.SECONDS) } 
                .retryWhen { errors -> errors.delay(1, TimeUnit.SECONDS) }
                .filter({ it.status == "UpdatesComplete" })
                .take(1)  // Take the first valid value and complete
        }
        .subscribe({
             // Subscription stuff
        )}
    

    一点解释——

    • repeatWhen/retryWhen 将每秒尝试一次请求。
    • filter 将导致状态错误的元素被忽略。
    • 当您获得第一个status == "UpdatesComplete" 元素时,take(1) 将发出该值并完成——这将具有取消重试的效果。

    注意:如果出现错误,永远重试网络请求通常是错误的做法。我建议您修改上面的retryWhen 以适合您在网络故障时终止的用例。例如,您可以重试 3 次,然后传播错误。有关如何做到这一点的一些示例,请参阅this article。在repeatWhen/retryWhen上也是一个很好的参考。

    【讨论】:

    • 我需要使用状态返回为待处理时传入的数据,因此在过滤器中我使用该数据。否则完美。谢谢:)
    【解决方案2】:

    retry()retryWhen() 都响应 Observable 中的 onError 事件,这就是它实际上没有重试的原因;您没有在 pollResults() Observable 中收到这些 onError 事件。现在,您的重试代码实际上并不依赖于 JSON 响应。

    我会考虑两种方法来解决这个问题:

    1. 如果 JSON 响应不令人满意,则在 pollResults() Observable 中抛出异常。这应该会触发retryWhen()。您需要在 Observable 某处对其进行测试。
    2. 像这样重组你的 Observable:

    `

    lateinit var pollUrl: String
    skyScannerInteractor.createSession("LHR", "AKL", "2018-04-20", "2018-04-22")
    .doOnSubscribe {
        loading.postValue(true)
    }
    .flatMap { url ->
        pollUrl = url
        skyScannerInteractor.pollResults(pollUrl)    
    }
    .doOnNext {
        if (it.status != "UpdatesComplete") {
             throw IOException("Updates not complete.") //Trigger onError
         }
    }
    .retryWhen { //Retry the Observable (createSession) when onError is called         
        it.delay(1000, TimeUnit.MILLISECONDS)
    }
    .subscribe({
        // Will give result only when UpdatesComplete
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-07
      • 2017-05-10
      • 2011-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-30
      • 1970-01-01
      相关资源
      最近更新 更多