代码之家  ›  专栏  ›  技术社区  ›  Josh Laird

轮询第二个URL,直到JSON返回预期参数

  •  1
  • Josh Laird  · 技术社区  · 7 年前

    我使用的是一个旅行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
    )}
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   iagreen    7 年前

    我假设你 pollResults(url) 方法返回 Single Observable 它的行为就像一个单一的函数--它返回一个结果,然后 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公司 以适合您在网络故障时终止的用例。例如,您可以重试三次,然后传播错误。看见 this article 有关如何做到这一点的一些示例。这也是一个很好的参考 重复时间/重试时间

        2
  •  1
  •   urgentx Galeb Nassri    7 年前

    retry() retryWhen() 两者都对可观察到的onError事件做出响应,这就是为什么它实际上没有重试;您在您的 pollResults() 可观察到。现在,您的重试代码实际上并不依赖于JSON响应。

    对此,我有两种想法:

    1. 在中引发异常 pollResults() 如果JSON响应不令人满意,则可以观察到。这将触发 retryWhen() .你需要在可观察的某处进行测试。
    2. 像这样重新组织您的可观察对象:

    `

    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
    }