如何在Retrofit和RxJava2中处理成功和失败响应?

时间:2018-11-16 12:53:21

标签: android kotlin retrofit2 rx-java2

我有以下要求:

@POST("devices/link/")
    fun linkDevice(
        @Body deviceInfo: DeviceInfo
    ): Single<Response<UserDevice>>

我想实现以下目标:

  1. 如果请求成功,则获取DeviceInfo并根据状态代码向分析报告事件

  2. 如果请求失败,请获取异常,将其转换并重新抛出。

因此,代码是:

fun linkDevice(): Single<UserDevice> {
    val deviceInfo = deviceUtil.getDeviceInfo()

    return devicesService
        .linkDevice(deviceInfo)
        .onErrorResumeNext { e ->
            val transformedException = transformRequestException(e) { httpException ->
                return@transformRequestException when (httpException.code()) {
                    409 -> DeviceAlreadyLinkedException()
                    else -> null
                }
            }
            Single.error(transformedException)
        }
        .flatMap { response ->
            if (response.isSuccessful) {
                val userDevice = response.body()

                userDevice?.let {
                    userPreferences.setDeviceId(it.id)
                }

                when (response.code()) {
                    200 -> {
                        // TODO: Analytics
                    }
                    201 -> {
                        // TODO: Analytics
                    }
                }

                Single.just(userDevice)
            } else {
                throw ApiException()
            }
        }
}

/**
 * Transform exception that came from request
 * By default, handles only network and HTTP 401 exceptions, but can contain custom logic, passed with specialTransformer
 */
fun transformRequestException(
    e: Throwable,
    specialTransformer: ((httpException: HttpException) -> Exception?)? = null
): Exception {
    return if (e is HttpException) {
        if (e.code() == 401) {
            NotAuthenticatedException()
        } else {
            specialTransformer?.invoke(e) ?: ApiException()
        }
    } else {
        NetworkException()
    }
}

但是此代码不起作用,如果我对Response对象进行操作,则仅对我的Retrofit服务中的Single<UserDevice>起作用。

但是,使用Single<UserDevice>我无法获得2XX码。

那么,如何实现所需的行为?

1 个答案:

答案 0 :(得分:0)

所以,到目前为止,我已经解决了以下问题:

data class RequestResult<T>(
    val data: T,
    val code: Int
)

fun <T> transformResponse(response: Response<T>): Single<RequestResult<T>> {
    if (response.isSuccessful) {
        return Single.just(RequestResult(response.body()!!, response.code()))
    } else {
        throw HttpException(response)
    }
}

fun <T> transformEmptyResponse(response: Response<T>): Completable {
    if (response.isSuccessful) {
        return Completable.complete()
    } else {
        throw HttpException(response)
    }
}

并且:

fun linkDevice(): Single<UserDevice> {
    val deviceInfo = deviceUtil.getDeviceInfo()

    return devicesService
        .linkDevice(deviceInfo)
        .flatMap { transformResponse(it) }
        .flatMap { requestResult ->
            requestResult.data.let { userDevice ->
                userPreferences.setDeviceId(userDevice.id)
                when (requestResult.code) {
                    200 -> {
                        // TODO: Analytics
                    }
                    201 -> {
                        // TODO: Analytics
                    }
                }

                Single.just(userDevice)
            }
        }
        .onErrorResumeNext { e ->
            val transformedException = transformRequestException(e) { httpException ->
                return@transformRequestException when (httpException.code()) {
                    409 -> DeviceAlreadyLinkedException()
                    else -> null
                }
            }
            Single.error(transformedException)
        }
}

看起来很像hack,但是我没有找到更好的解决方案,而且它行得通。