Android RxJava2 - 如何在抛出错误时进行 api 调用?

Android RxJava2 - How to make api call when error is thrown?

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

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 调用在订阅方法中被 returned,因为注销和 apiCall3 return 空尸体。如果 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 调用,如果第一个失败,则向订阅者发送一个可抛出的对象,如果第一个成功并且之后失败,则进行另一个 api 调用。

我通过抛出自定义异常而不是向下传递 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)
    })