如何制作 RxErrorHandlingCallAdapterFactory?
How to make RxErrorHandlingCallAdapterFactory?
我找到了 this。
但在新版本 compile 'com.squareup.retrofit2:adapter-rxjava:2.2.0'
中,CallAdapter 有两个参数
CallAdapter<?,?>
如果从 CallAdapter<?,?>
如何将 RxCallAdapterWrapper 修改为 implement
免责声明:我是您引用的博客 post 的作者
最初的 post 是作为概念证明和 RxJava 2 的,所以我也更容易用那个版本来解释,但我会尝试涵盖更多的内容。我猜您使用的是版本 1,因为您谈论的是 adapter-rxjava
而不是 adapter-rxjava2
。也就是说,版本 1 的实现应该非常简单,只需使用正确的导入即可。
这是我使用 RxJava 2 所做的:
class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
private final RxJava2CallAdapterFactory original;
private RxErrorHandlingCallAdapterFactory() {
original = RxJava2CallAdapterFactory.create();
}
public static CallAdapter.Factory create() {
return new RxErrorHandlingCallAdapterFactory();
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit));
}
private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> {
private final Retrofit retrofit;
private final CallAdapter<R, Object> wrapped;
public RxCallAdapterWrapper(Retrofit retrofit, CallAdapter<R, Object> wrapped) {
this.retrofit = retrofit;
this.wrapped = wrapped;
}
@Override
public Type responseType() {
return wrapped.responseType();
}
@Override
public Object adapt(Call<R> call) {
Object result = wrapped.adapt(call);
if (result instanceof Single) {
return ((Single) result).onErrorResumeNext(new Function<Throwable, SingleSource>() {
@Override
public SingleSource apply(@NonNull Throwable throwable) throws Exception {
return Single.error(asRetrofitException(throwable));
}
});
}
if (result instanceof Observable) {
return ((Observable) result).onErrorResumeNext(new Function<Throwable, ObservableSource>() {
@Override
public ObservableSource apply(@NonNull Throwable throwable) throws Exception {
return Observable.error(asRetrofitException(throwable));
}
});
}
if (result instanceof Completable) {
return ((Completable) result).onErrorResumeNext(new Function<Throwable, CompletableSource>() {
@Override
public CompletableSource apply(@NonNull Throwable throwable) throws Exception {
return Completable.error(asRetrofitException(throwable));
}
});
}
return result;
}
private RetrofitException asRetrofitException(Throwable throwable) {
// We had non-200 http error
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
Response response = httpException.response();
return RetrofitException.httpError(response.raw().request().url().toString(), response, retrofit);
}
// A network error happened
if (throwable instanceof IOException) {
return RetrofitException.networkError((IOException) throwable);
}
// We don't know what happened. We need to simply convert to an unknown error
return RetrofitException.unexpectedError(throwable);
}
}
}
没有重大变化,只是一些 return 类型的变化。现在,如果您查看 RxJava2CallAdapter
它实现了 CallAdapter<R, Object>
,那么我们需要考虑这一点。
然后我添加了一些实例类型检查,以确保我们 return 是正确的。
真正重要的部分是确保导入正确的包。改造适配器检查特定 类。我遇到的一个问题是错误的导入,并且在某些情况下我正在检查 Throwable
是否是 com.jakewharton.retrofit2.adapter.HttpException
的实例,而它实际上是 retrofit2.adapter.rxjava2.HttpException
.[=18= 的实例]
希望对您有所帮助
已将 更新为 kotlin
样式和
rxjava1:
com.squareup.retrofit2:adapter-rxjava:2.5.0
与 io.reactivex:rxjava:1.3.8
RxErrorHandlingCallAdapterFactory.kt
import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import rx.Observable
import java.io.IOException
import java.lang.reflect.Type
/**
* Created by Nikolay Unuchek on 28.11.2016.
*/
internal class RxErrorHandlingCallAdapterFactory private constructor() : CallAdapter.Factory() {
private val original: RxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create()
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
return RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit) ?: return null)
}
private class RxCallAdapterWrapper<R>(
private val retrofit: Retrofit,
private val wrapped: CallAdapter<R, *>
) : CallAdapter<R, Any> {
override fun responseType(): Type {
return wrapped.responseType()
}
override fun adapt(call: Call<R>): Any {
val result = wrapped.adapt(call)
if (result is Observable<*>) {
return result.onErrorResumeNext { throwable -> Observable.error(asRetrofitException(throwable as Throwable)) }
}
return result
}
private fun asRetrofitException(throwable: Throwable): RetrofitException {
// We had non-200 http error
if (throwable is HttpException) {
val response = throwable.response()
return RetrofitException.httpError(response.raw().request.url.toString(), response, throwable)
}
// A network error happened
return if (throwable is IOException) {
RetrofitException.networkError(throwable)
} else RetrofitException.unexpectedError(throwable)
// We don't know what happened. We need to simply convert to an unknown error
}
}
companion object {
fun create(): CallAdapter.Factory {
return RxErrorHandlingCallAdapterFactory()
}
}
}
RetrofitException.kt
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
class RetrofitException
private constructor(
message: String?,
/**
* The request URL which produced the error.
*/
val url: String?,
/**
* Response object containing status code, headers, body, etc.
*/
val response: Response<*>?,
/**
* The event kind which triggered this error.
*/
val kind: Kind,
exception: Throwable
) : RuntimeException(message, exception) {
override fun toString(): String {
return super.toString() + " : " + kind + " : " + url + " : " + response?.errorBody()?.string()
}
/**
* Identifies the event kind which triggered a [RetrofitException].
*/
enum class Kind {
/**
* An [IOException] occurred while communicating to the server.
*/
NETWORK,
/**
* A non-200 HTTP status code was received from the server.
*/
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
companion object {
fun httpError(url: String, response: Response<*>, httpException: HttpException): RetrofitException {
val message = response.code().toString() + " " + response.message()
return RetrofitException(message, url, response, Kind.HTTP, httpException)
}
fun networkError(exception: IOException): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.NETWORK, exception)
}
fun unexpectedError(exception: Throwable): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.UNEXPECTED, exception)
}
fun asRetrofitException(throwable: Throwable): RetrofitException {
if (throwable is RetrofitException) {
return throwable
}
// We had non-200 http error
if (throwable is HttpException) {
val response = throwable.response()
return httpError(response.raw().request().url().toString(), response, throwable)
}
// A network error happened
return if (throwable is IOException) {
networkError(throwable)
} else unexpectedError(throwable)
// We don't know what happened. We need to simply convert to an unknown error
}
}
}
rxjava2:
com.squareup.retrofit2:adapter-rxjava2:2.6.0
与 io.reactivex.rxjava2:rxjava:2.2.9
RxErrorHandlingCallAdapterFactory.kt
import by.gramophone.api.errorhandling.RetrofitException.Companion.asRetrofitException
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.functions.Function
import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import java.lang.reflect.Type
/**
* Created by Nikolay Unuchek on 28.11.2016.
*/
internal class RxErrorHandlingCallAdapterFactory private constructor() : CallAdapter.Factory() {
private val original = RxJava2CallAdapterFactory.create()
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
return RxCallAdapterWrapper(original.get(returnType, annotations, retrofit) ?: return null)
}
private class RxCallAdapterWrapper<R>(private val wrapped: CallAdapter<R, *>) : CallAdapter<R, Any> {
override fun responseType(): Type {
return wrapped.responseType()
}
override fun adapt(call: Call<R>): Any {
return when (val result = wrapped.adapt(call)) {
is Single<*> -> result.onErrorResumeNext(Function { throwable -> Single.error(asRetrofitException(throwable)) })
is Observable<*> -> result.onErrorResumeNext(Function { throwable -> Observable.error(asRetrofitException(throwable)) })
is Completable -> result.onErrorResumeNext (Function{ throwable -> Completable.error(asRetrofitException(throwable)) } )
else -> result
}
}
}
companion object {
fun create(): CallAdapter.Factory {
return RxErrorHandlingCallAdapterFactory()
}
}
}
RetrofitException.kt
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
class RetrofitException
private constructor(
message: String?,
/**
* The request URL which produced the error.
*/
val url: String?,
/**
* Response object containing status code, headers, body, etc.
*/
val response: Response<*>?,
/**
* The event kind which triggered this error.
*/
val kind: Kind,
exception: Throwable
) : RuntimeException(message, exception) {
override fun toString(): String {
return super.toString() + " : " + kind + " : " + url + " : " + response?.errorBody()?.string()
}
/**
* Identifies the event kind which triggered a [RetrofitException].
*/
enum class Kind {
/**
* An [IOException] occurred while communicating to the server.
*/
NETWORK,
/**
* A non-200 HTTP status code was received from the server.
*/
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
companion object {
fun httpError(url: String, response: Response<*>, httpException: HttpException): RetrofitException {
val message = response.code().toString() + " " + response.message()
return RetrofitException(message, url, response, Kind.HTTP, httpException)
}
fun networkError(exception: IOException): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.NETWORK, exception)
}
fun unexpectedError(exception: Throwable): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.UNEXPECTED, exception)
}
fun asRetrofitException(throwable: Throwable): RetrofitException {
if (throwable is RetrofitException) {
return throwable
}
// We had non-200 http error
if (throwable is HttpException) {
val response = throwable.response()
return httpError(response.raw().request().url().toString(), response, throwable)
}
// A network error happened
return if (throwable is IOException) {
networkError(throwable)
} else unexpectedError(throwable)
// We don't know what happened. We need to simply convert to an unknown error
}
}
}
我找到了 this。
但在新版本 compile 'com.squareup.retrofit2:adapter-rxjava:2.2.0'
中,CallAdapter 有两个参数
CallAdapter<?,?>
如果从 CallAdapter<?,?>
implement
免责声明:我是您引用的博客 post 的作者
最初的 post 是作为概念证明和 RxJava 2 的,所以我也更容易用那个版本来解释,但我会尝试涵盖更多的内容。我猜您使用的是版本 1,因为您谈论的是 adapter-rxjava
而不是 adapter-rxjava2
。也就是说,版本 1 的实现应该非常简单,只需使用正确的导入即可。
这是我使用 RxJava 2 所做的:
class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
private final RxJava2CallAdapterFactory original;
private RxErrorHandlingCallAdapterFactory() {
original = RxJava2CallAdapterFactory.create();
}
public static CallAdapter.Factory create() {
return new RxErrorHandlingCallAdapterFactory();
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit));
}
private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> {
private final Retrofit retrofit;
private final CallAdapter<R, Object> wrapped;
public RxCallAdapterWrapper(Retrofit retrofit, CallAdapter<R, Object> wrapped) {
this.retrofit = retrofit;
this.wrapped = wrapped;
}
@Override
public Type responseType() {
return wrapped.responseType();
}
@Override
public Object adapt(Call<R> call) {
Object result = wrapped.adapt(call);
if (result instanceof Single) {
return ((Single) result).onErrorResumeNext(new Function<Throwable, SingleSource>() {
@Override
public SingleSource apply(@NonNull Throwable throwable) throws Exception {
return Single.error(asRetrofitException(throwable));
}
});
}
if (result instanceof Observable) {
return ((Observable) result).onErrorResumeNext(new Function<Throwable, ObservableSource>() {
@Override
public ObservableSource apply(@NonNull Throwable throwable) throws Exception {
return Observable.error(asRetrofitException(throwable));
}
});
}
if (result instanceof Completable) {
return ((Completable) result).onErrorResumeNext(new Function<Throwable, CompletableSource>() {
@Override
public CompletableSource apply(@NonNull Throwable throwable) throws Exception {
return Completable.error(asRetrofitException(throwable));
}
});
}
return result;
}
private RetrofitException asRetrofitException(Throwable throwable) {
// We had non-200 http error
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
Response response = httpException.response();
return RetrofitException.httpError(response.raw().request().url().toString(), response, retrofit);
}
// A network error happened
if (throwable instanceof IOException) {
return RetrofitException.networkError((IOException) throwable);
}
// We don't know what happened. We need to simply convert to an unknown error
return RetrofitException.unexpectedError(throwable);
}
}
}
没有重大变化,只是一些 return 类型的变化。现在,如果您查看 RxJava2CallAdapter
它实现了 CallAdapter<R, Object>
,那么我们需要考虑这一点。
然后我添加了一些实例类型检查,以确保我们 return 是正确的。
真正重要的部分是确保导入正确的包。改造适配器检查特定 类。我遇到的一个问题是错误的导入,并且在某些情况下我正在检查 Throwable
是否是 com.jakewharton.retrofit2.adapter.HttpException
的实例,而它实际上是 retrofit2.adapter.rxjava2.HttpException
.[=18= 的实例]
希望对您有所帮助
已将 kotlin
样式和
rxjava1:
com.squareup.retrofit2:adapter-rxjava:2.5.0
与 io.reactivex:rxjava:1.3.8
RxErrorHandlingCallAdapterFactory.kt
import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import rx.Observable
import java.io.IOException
import java.lang.reflect.Type
/**
* Created by Nikolay Unuchek on 28.11.2016.
*/
internal class RxErrorHandlingCallAdapterFactory private constructor() : CallAdapter.Factory() {
private val original: RxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create()
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
return RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit) ?: return null)
}
private class RxCallAdapterWrapper<R>(
private val retrofit: Retrofit,
private val wrapped: CallAdapter<R, *>
) : CallAdapter<R, Any> {
override fun responseType(): Type {
return wrapped.responseType()
}
override fun adapt(call: Call<R>): Any {
val result = wrapped.adapt(call)
if (result is Observable<*>) {
return result.onErrorResumeNext { throwable -> Observable.error(asRetrofitException(throwable as Throwable)) }
}
return result
}
private fun asRetrofitException(throwable: Throwable): RetrofitException {
// We had non-200 http error
if (throwable is HttpException) {
val response = throwable.response()
return RetrofitException.httpError(response.raw().request.url.toString(), response, throwable)
}
// A network error happened
return if (throwable is IOException) {
RetrofitException.networkError(throwable)
} else RetrofitException.unexpectedError(throwable)
// We don't know what happened. We need to simply convert to an unknown error
}
}
companion object {
fun create(): CallAdapter.Factory {
return RxErrorHandlingCallAdapterFactory()
}
}
}
RetrofitException.kt
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
class RetrofitException
private constructor(
message: String?,
/**
* The request URL which produced the error.
*/
val url: String?,
/**
* Response object containing status code, headers, body, etc.
*/
val response: Response<*>?,
/**
* The event kind which triggered this error.
*/
val kind: Kind,
exception: Throwable
) : RuntimeException(message, exception) {
override fun toString(): String {
return super.toString() + " : " + kind + " : " + url + " : " + response?.errorBody()?.string()
}
/**
* Identifies the event kind which triggered a [RetrofitException].
*/
enum class Kind {
/**
* An [IOException] occurred while communicating to the server.
*/
NETWORK,
/**
* A non-200 HTTP status code was received from the server.
*/
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
companion object {
fun httpError(url: String, response: Response<*>, httpException: HttpException): RetrofitException {
val message = response.code().toString() + " " + response.message()
return RetrofitException(message, url, response, Kind.HTTP, httpException)
}
fun networkError(exception: IOException): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.NETWORK, exception)
}
fun unexpectedError(exception: Throwable): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.UNEXPECTED, exception)
}
fun asRetrofitException(throwable: Throwable): RetrofitException {
if (throwable is RetrofitException) {
return throwable
}
// We had non-200 http error
if (throwable is HttpException) {
val response = throwable.response()
return httpError(response.raw().request().url().toString(), response, throwable)
}
// A network error happened
return if (throwable is IOException) {
networkError(throwable)
} else unexpectedError(throwable)
// We don't know what happened. We need to simply convert to an unknown error
}
}
}
rxjava2:
com.squareup.retrofit2:adapter-rxjava2:2.6.0
与 io.reactivex.rxjava2:rxjava:2.2.9
RxErrorHandlingCallAdapterFactory.kt
import by.gramophone.api.errorhandling.RetrofitException.Companion.asRetrofitException
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.functions.Function
import retrofit2.Call
import retrofit2.CallAdapter
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import java.lang.reflect.Type
/**
* Created by Nikolay Unuchek on 28.11.2016.
*/
internal class RxErrorHandlingCallAdapterFactory private constructor() : CallAdapter.Factory() {
private val original = RxJava2CallAdapterFactory.create()
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
return RxCallAdapterWrapper(original.get(returnType, annotations, retrofit) ?: return null)
}
private class RxCallAdapterWrapper<R>(private val wrapped: CallAdapter<R, *>) : CallAdapter<R, Any> {
override fun responseType(): Type {
return wrapped.responseType()
}
override fun adapt(call: Call<R>): Any {
return when (val result = wrapped.adapt(call)) {
is Single<*> -> result.onErrorResumeNext(Function { throwable -> Single.error(asRetrofitException(throwable)) })
is Observable<*> -> result.onErrorResumeNext(Function { throwable -> Observable.error(asRetrofitException(throwable)) })
is Completable -> result.onErrorResumeNext (Function{ throwable -> Completable.error(asRetrofitException(throwable)) } )
else -> result
}
}
}
companion object {
fun create(): CallAdapter.Factory {
return RxErrorHandlingCallAdapterFactory()
}
}
}
RetrofitException.kt
import retrofit2.HttpException
import retrofit2.Response
import java.io.IOException
class RetrofitException
private constructor(
message: String?,
/**
* The request URL which produced the error.
*/
val url: String?,
/**
* Response object containing status code, headers, body, etc.
*/
val response: Response<*>?,
/**
* The event kind which triggered this error.
*/
val kind: Kind,
exception: Throwable
) : RuntimeException(message, exception) {
override fun toString(): String {
return super.toString() + " : " + kind + " : " + url + " : " + response?.errorBody()?.string()
}
/**
* Identifies the event kind which triggered a [RetrofitException].
*/
enum class Kind {
/**
* An [IOException] occurred while communicating to the server.
*/
NETWORK,
/**
* A non-200 HTTP status code was received from the server.
*/
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
companion object {
fun httpError(url: String, response: Response<*>, httpException: HttpException): RetrofitException {
val message = response.code().toString() + " " + response.message()
return RetrofitException(message, url, response, Kind.HTTP, httpException)
}
fun networkError(exception: IOException): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.NETWORK, exception)
}
fun unexpectedError(exception: Throwable): RetrofitException {
return RetrofitException(exception.message, null, null, Kind.UNEXPECTED, exception)
}
fun asRetrofitException(throwable: Throwable): RetrofitException {
if (throwable is RetrofitException) {
return throwable
}
// We had non-200 http error
if (throwable is HttpException) {
val response = throwable.response()
return httpError(response.raw().request().url().toString(), response, throwable)
}
// A network error happened
return if (throwable is IOException) {
networkError(throwable)
} else unexpectedError(throwable)
// We don't know what happened. We need to simply convert to an unknown error
}
}
}