kotlin封裝Retrofit網絡請求

先看看最後使用效果。java

ApiManager.apiService
                    .update("1.0")
                    .composeDefault()//統一處理異常,請求後臺異常throw ApiException ,異常信息爲後臺給的異常內容
                    .subscribeExtApi({
                        //成功返回
                        toastInfo(it.toString())
                    }, { e ->
                        toastInfo("更新失敗")
                    }, {
                        //請求完成
                    },isToast = true
                    )   
複製代碼

一、先封裝retrofit,api

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
    }
}
複製代碼

二、interface 接口bash

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

三、初始化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)
    }
}
複製代碼

四、封裝通用的失敗處理。app

請求返回是BaseBean,code爲12000是成功,其他則是是失敗,拋出異常ApiException。ui

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
                }
複製代碼

五、處理成功失敗回調。this

這裏使用 可本身添加擴展,這裏只添加了是否toast失敗信息。
url

/**
 * @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()
}
複製代碼
相關文章
相關標籤/搜索