How to make RxErrorHandlingCallAdapterFactory?

后端 未结 2 510
礼貌的吻别
礼貌的吻别 2021-02-02 18:30

I found this.

But in new ver compile \'com.squareup.retrofit2:adapter-rxjava:2.2.0\' at CallAdapter it has two params CallAdapter

2条回答
  •  既然无缘
    2021-02-02 18:33

    Updated anwer of Fred to kotlin style and

    rxjava1:

    com.squareup.retrofit2:adapter-rxjava:2.5.0 with 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, retrofit: Retrofit): CallAdapter<*, *>? {
            return RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit) ?: return null)
        }
    
        private class RxCallAdapterWrapper(
            private val retrofit: Retrofit,
            private val wrapped: CallAdapter
        ) : CallAdapter {
    
            override fun responseType(): Type {
                return wrapped.responseType()
            }
    
            override fun adapt(call: Call): 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 with 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, retrofit: Retrofit): CallAdapter<*, *>? {
            return RxCallAdapterWrapper(original.get(returnType, annotations, retrofit) ?: return null)
        }
    
        private class RxCallAdapterWrapper(private val wrapped: CallAdapter) : CallAdapter {
    
            override fun responseType(): Type {
                return wrapped.responseType()
            }
    
            override fun adapt(call: Call): 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
            }
        }
    }
    

提交回复
热议问题