kotlin封装Retrofit网络请求

2,925 阅读2分钟

先看看最后使用效果。

ApiManager.apiService
                    .update("1.0")
                    .composeDefault()//统一处理异常,请求后台异常throw ApiException ,异常信息为后台给的异常内容
                    .subscribeExtApi({
                        //成功返回
                        toastInfo(it.toString())
                    }, { e ->
                        toastInfo("更新失败")
                    }, {
                        //请求完成
                    },isToast = true
                    )   

1、先封装retrofit,

object CommonConst {
    const val REQUEST_OUTTIME = 10_000L
    //超时时间 ms
    const val DOWNLOAD_OUTTIME = 16_000L
    const val UPLOAD_OUTTIME = 16_000L
    //retrofit baseurl 必须以“/”结尾
    var BASE_URL = "http://www.baidu.com/"
}

class RequestApiManager() {
    private var retrofit: Retrofit? = null
    private var client: OkHttpClient? = null
    private object SingletonHolder {
        val INSTANCE = RequestApiManager()
    }
    
    fun initRetrofit(clientBuilder: (builder: OkHttpClient.Builder) -> Unit = {}, retrofitBuilder: (builder: Retrofit.Builder) -> Unit = {}, baseUrl: String = CommonConst.BASE_URL) {
        if (client == null) {
            client = OkHttpClient.Builder().apply {
                connectTimeout(CommonConst.REQUEST_OUTTIME, TimeUnit.MILLISECONDS)
                if (BuildConfig.DEBUG) {
                    //添加日志
                    addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY })
                }
                clientBuilder(this);
            }.build()
        }

        if (retrofit == null) {
            retrofit = Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
//                .addConverterFactory(CustomGsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .apply {
                        retrofitBuilder(this);
                    }
                    .build()
        }
    }

    //这里返回一个泛型类,主要返回的是定义的接口类
    fun <T> createService(clazz: Class<T>): T {
        if (retrofit == null) {
            initRetrofit();
        }
        return retrofit!!.create(clazz)
    }

    companion object {
        val instance: RequestApiManager
            get() = SingletonHolder.INSTANCE
    }
}

2、interface 接口

interface ApiService {
    //检查版本更新
    @GET("http://xxxx/checkForceVersion")
    fun update(@Query("user_version") version: String): Observable<BaseBean<String>>
}

3、初始化retrofit

object ApiManager {
    var apiService by NotNullSingle<ApiService>()
    //application 初始化
    fun initApiService() {
        apiService = RequestApiManager.instance.apply {
            initRetrofit({ clientBuilder ->
                //添加拦截器
            }, { retrofitBuilder ->
            }, "http://www.test.com")
        }.createService(ApiService::class.java)
    }
}

4、封装通用的失败处理。

请求返回是BaseBean,code为12000是成功,其余则是是失败,抛出异常ApiException。

class BaseBean<T> : Serializable {
    var code: Int = 0
    var msg: String = ""
    var data: T? = null
}

//请求数据返回失败
class ApiException constructor(var code: Int, msg: String?, result: String?) : RuntimeException(msg)

fun <T> Observable<T>.composeDefault(): Observable<T> =
        subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io()).map { t ->
                    var msg = "请求异常"
                     when (t) {
                        is BaseBean<*> -> {
                            msg = t.msg
                            if (t.code != 12000) {
                                throw ApiException(t.code, msg, GsonUtil().toJson(t))
                            }
                        }
                    }
                    t
                }

5、处理成功失败回调。

这里使用 可自己添加扩展,这里只添加了是否toast失败信息。

/**
 * @param onNext 成功
 * @param onError 失败 不传默认toast ApiException的异常信息,可以传onError 能toast自己的信息 例如:{toastInfo("添加失败")}
 * @param onComplete 完成
 * @param isToast 是否toast失败信息
 */
fun <T> Observable<T>.subscribeExtApi(onNext: (result: T) -> Unit,
                                      onError: ((e: Throwable) -> Unit)? = null,
                                      onComplete: (() -> Unit)? = null,
                                      onSubscribe: ((disposable: Disposable) -> Unit)? = null,
                                      isToast: Boolean = true): Disposable {

    return LambdaObserver<T>(
            { result ->
                onNext(result)
            },
            { e ->
                errorToast(e) {
                    onError?.invoke(e) ?: run {
                        if (isToast) toastErrorNet(e)
                    }
                }
            },
            {
                onComplete?.invoke()
                //todo 完成取消进度框
            },
            {
                onSubscribe?.invoke(it)
                //todo 开始请求显示进度框
            })
            .apply {
                subscribe(this)
            }
}

private fun errorToast(e: Throwable, block: () -> Unit) {
    if (e is ApiException) {
        block()
    } else if (e is ConnectException || e is UnknownHostException) {
        toastInfo("网络未连接")
    } else if (e is TimeoutException || e is SocketTimeoutException) {
        toastInfo("网络超时")
    } else if (e is JsonSyntaxException) {
        toastInfo("数据解析异常")
    } else {
        Logger.d("onError#${e.message}")
        if (BuildConfig.DEBUG) {
            toastInfo("未知异常${e.message}")
        } else {
            toastInfo("请求异常")
        }
    }
    e.printStackTrace()
}