我有以下要求:
@POST("devices/link/")
fun linkDevice(
@Body deviceInfo: DeviceInfo
): Single<Response<UserDevice>>
我想实现以下目标:
如果请求成功,则获取DeviceInfo并根据状态代码向分析报告事件
如果请求失败,请获取异常,将其转换并重新抛出。
因此,代码是:
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码。
那么,如何实现所需的行为?
答案 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,但是我没有找到更好的解决方案,而且它行得通。