【问题标题】:Android RxJava2 - How to make api call when error is thrown?Android RxJava2 - 抛出错误时如何进行api调用?
【发布时间】:2019-06-22 22:44:45
【问题描述】:

所以我目前正在使用 flatMap 将 API 调用链接在一起,它在我的用例中运行良好。如果我的一个调用返回一个失败的响应代码,那么我将传递一个错误单,其中包含一个可抛出的消息,该消息说明哪个调用失败并且它继续进行。这是我现在的做法:

dataManager.apiCall1(dataManager.sessionId!!)
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.ui())
        .flatMap{apiCall1Response ->
            if (apiCall1Response.isSuccessful && apiCall1Response.body() != null) {
                // First api call was successful, execute api call 2.
                return@flatMap dataManager.apiCall2(apiCall1Response.importantVal)
            } else {
                // First api call failed 
                return@flatMap Single.error<Throwable>(Throwable("First api call failed."))
            }
        }.flatMap{apiCall2Response ->
            if (apiCall2Response != null && apiCall2Response.isSuccessful && apiCall2Response.body() != null) {
                // Second api call was successful, execute api call 3.
                return@flatMap dataManager.apiCall3(apiCall2Response.importantVal)
            } else if (apiCall2Response is Throwable) {
                // Api Call 1 Failed.
                return@flatMap Single.error<Throwable>(apiCall2Response)
            } else {
                // Second api call failed
                return@flatMap Single.error<Throwable>(Throwable("Second api call failed."))
            }
        }.subscribe({apiCall3Response ->
            if (apiCall3Response is Response<*> && apiCall3Response.body() != null) {
               // Success!
               navigator?.successful(response)
            } else if (apiCall3Response is Throwable) {
               // Something failed from before.
               navigator?.handleError(apiCall3Response)
            } else {
               // Third api call failed, handle error
               navigator!!.handleError(Throwable("Api call 3 failed."))
            }
        }, {throwable ->
            navigator!!.handleError(throwable)
        })

好吧,现在我意识到如果我的第一个 api 调用成功并且我的任何其他调用失败,我需要进行不同的 api 调用。这是登录用户的一系列调用,如果登录调用成功,但下一次调用失败,我们需要调用 api 注销端点。我知道在 subscribe() 方法中创建另一个单曲是不好的做法,所以我不想这样做。我宁愿通过注销调用,但问题是无法知道订阅方法中返回的是哪个 api 调用,因为注销和 apiCall3 都返回空主体。如果 apiCall3 失败,我也想调用注销端点,但不确定这是否可能。这是我想要做的:

dataManager.apiCall1(dataManager.sessionId!!)
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.ui())
        .flatMap{apiCall1Response ->
            if (apiCall1Response.isSuccessful && apiCall1Response.body() != null) {
                // First api call was successful, execute api call 2.
                return@flatMap dataManager.apiCall2(apiCall1Response.importantVal)
            } else {
                // First api call failed 
                return@flatMap Single.error<Throwable>(Throwable("First api call failed."))
            }
        }.flatMap{apiCall2Response ->
            if (apiCall2Response != null && apiCall2Response.isSuccessful && apiCall2Response.body() != null) {
                // Second api call was successful, execute api call 3.
                return@flatMap dataManager.apiCall3(apiCall2Response.importantVal)
            } else if (apiCall2Response is Throwable) {
                // Api Call 1 Failed.
                return@flatMap Single.error<Throwable>(apiCall2Response)
            } else {
                // Second api call failed, logout
                return@flatMap dataManager.logoutApiCall()
            }
        }.subscribe({apiCall3OrLogoutResponse ->
            // I would like to be able to determine which call this response is from. That is the question. 
            if (apiCall3OrLogoutResponse is Response<*> && apiCall3OrLogoutResponse.body() != null) {
               // Success!
               navigator?.successful(response)
            } else if (apiCall3OrLogoutResponse is Throwable) {
               // Something failed from before.
               navigator?.handleError(apiCall3OrLogoutResponse)
            } else {
               // Third api call or logout call failed, handle error
               if (apiCall3OrLogoutResponse is ApiCall3) {
                  // Api Call 3 failed. 
                  // Somehow call logout api endpoint
               } else if (apiCall3OrLogoutResponse is LogoutCall {
                  // Logout call failed.
                  navigator?.handleError(Throwable("Logout failed."))  
               }       
            }
        }, {throwable ->
            navigator!!.handleError(throwable)
        })

有没有更好的方法来做到这一点?我的用例是进行三个连续的 api 调用,如果第一个失败,则向订阅者发送一个 throwable,如果第一个成功并且之后任何失败,则进行另一个 api 调用。

【问题讨论】:

    标签: android mvvm kotlin rx-java2 rx-android


    【解决方案1】:

    我通过抛出自定义异常而不是传递 Single.error 并在 flatMapCompletable 而不是订阅中检查我的最终调用来解决这个问题。然后,如果异常不是登录异常,我会在 doOnError 中调用注销端点。

    dataManager.apiCall1(dataManager.sessionId!!)
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.ui())
        .flatMap{apiCall1Response ->
            if (apiCall1Response.isSuccessful && apiCall1Response.body() != null) {
                // First api call was successful, execute api call 2.
                return@flatMap dataManager.apiCall2(apiCall1Response.importantVal)
            } else {
                // First api call failed 
                throw ApiCall1Exception("Api Call 1 failed.")
            }
        }.flatMap{apiCall2Response ->
            if (apiCall2Response != null && apiCall2Response.isSuccessful && apiCall2Response.body() != null) {
                // Second api call was successful, execute api call 3.
                return@flatMap dataManager.apiCall3(apiCall2Response.importantVal)
            } else {
                // Second api call failed
                throw Throwable("Api call 2 failed.")
            }
        }.flatMapCompletable{apiCall3Response ->
            if (apiCall3Response.body() != null) {
                // All api calls were successful!
                Completable.complete()
            } else {
                // Third api call failed.
                throw Throwable("Api call 3 failed.")
            }    
        }.doOnError{throwable ->
            if (throwable !is ApiCall1Exception) {
                // Api call 1 was successful, but something else failed, call logout endpoint.
                dataManager.logout()
                      .subscribeOn(schedulerProvider.io())
                      .observeOn(schedulerProvider.ui())
            }
        }.subscribe({
            // Success!
            navigator?.success()
        }, {throwable ->
            // Something failed!
            navigator?.handleError(throwable)
        })
    

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2015-11-07
      • 1970-01-01
      • 2017-06-06
      • 1970-01-01
      • 2018-12-29
      相关资源
      最近更新 更多