kotlin 简单封装 网络访问框架。

suspend fun <T> loadHttp(
   // 默认实现{},即参数可空
    start: () -> Unit = {},
    // suspend 修饰的函数,返回值ResultData<T>,没有默认实现,即参数不可空
    // 函数的参数为T,没有默认实现,即参数不可空
    end: () -> Unit = {},
     request: suspend () -> BaseResponse<T>
): Result<T> {
    // 在主线程(Dispatchers.Main)执行

    try {
        // 1.函数开始执行,先调用start()方法,给View做准备工作,如:显示loading
        start()
        // 2.发起网络请求
        val data = withTimeout(10*000) {//使用的时候自行设置超时时间
            request()
        }

        if (data.errorCode == 0) {
            // 3.请求成功,返回响应
            if (data.data == null) {
                return Result.success("" as T)
            }
            return Result.success(data.data)
        } else {
            return Result.failure(ApiException(data.errorCode, data.errorMsg))
        }
    } catch (e: Throwable) {
        // 可根据具体异常显示具体错误提示
        return Result.failure(e)
    } finally {
        end()
    }

}

BaseResponse//根据后台返回 适当修改。

data class BaseResponse<out T>(val errorMsg: String, val errorCode: Int, val data: T) : Serializable

RetrofitBuilder//拦截器请根据需求增加或者变动


object RetrofitBuilder {

    val cookieJar = PersistentCookieJar(
        SetCookieCache(),
        SharedPrefsCookiePersistor(MyApp.getApplication().baseContext)
    )

    private val cacheFile = File(MyApp.getApplication().cacheDir, "mycache")
    private val cache = Cache(cacheFile, 1024 * 1024 * 50)// 50M 的缓存大小
    private val okHttpClient: OkHttpClient
        get() {
            // create http client
            val httpClient = OkHttpClient.Builder()
                .cookieJar(cookieJar)
                // .addInterceptor(ReceivedCookiesInterceptor(MyApp.getApplication()))
                // .addInterceptor(AddCookiesInterceptor(MyApp.getApplication()))
                .addInterceptor(Interceptor { chain ->
                    val original = chain.request()

                    //header
                    val request =
                        original.newBuilder().method(original.method, original.body).build()

                    return@Interceptor chain.proceed(request)
                }).readTimeout(30, TimeUnit.SECONDS)

            httpClient.addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            httpClient.run {
                cache(cache)
                connectTimeout(5, TimeUnit.SECONDS)
                readTimeout(5, TimeUnit.SECONDS)
                writeTimeout(5, TimeUnit.SECONDS)
                retryOnConnectionFailure(true)//错误重连
            }
            return httpClient.build()
        }
    
    private fun getRetrofit(BASEURL: String): Retrofit {
        return Retrofit.Builder().client(okHttpClient).baseUrl(BASEURL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .addConverterFactory(ScalarsConverterFactory.create())
            .addCallAdapterFactory(FlowCallAdapterFactory.create()) //kotlin flow 支持
            .build() //Doesn't require the adapter
    }

    fun <T> createService(clazz: Class<T>, baseUrl: String): T =
        getRetrofit(baseUrl).create(clazz)

    inline fun <reified T> create(baseUrl: String): T = createService(T::class.java, baseUrl)
    fun clearCookie(){
        cookieJar.clear()
    }
}

错误统一处理:

open class ApiException : Exception {
    var errCode: Int
    var errMsg: String

    constructor(error: ERROR, e: Throwable? = null) : super(e) {
        errCode = error.code
        errMsg = error.errMsg
    }

    constructor(code: Int, msg: String, e: Throwable? = null) : super(e) {
        this.errCode = code
        this.errMsg = msg
    }
}

/**
 * 无网络连接异常
 */
class NoNetWorkException : IOException {
    var errCode: Int
    var errMsg: String

    constructor(error: ERROR, e: Throwable? = null) : super(e) {
        errCode = error.code
        errMsg = error.errMsg
    }
}

enum class ERROR(val code: Int, val errMsg: String) {

    /**
     * 对应HTTP的状态码
     */
    /**
     * 当前请求需要用户验证
     */
    UNAUTHORIZED(401, "当前请求需要用户验证"),

    /**
     * 资源不可用。服务器理解客户的请求,但拒绝处理它
     */
    FORBIDDEN(403, "资源不可用"),

    /**
     * 无法找到指定位置的资源
     */
    NOT_FOUND(404, "无法找到指定位置的资源"),

    /**
     * 在服务器许可的等待时间内,客户一直没有发出任何请求
     */
    REQUEST_TIMEOUT(408, "请求超时"),

    /**
     * 服务器遇到了意料不到的情况,不能完成客户的请求
     */
    INTERNAL_SERVER_ERROR(500, "服务器错误"),

    /**
     * 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答
     */
    BAD_GATEWAY(502, "非法应答"),

    /**
     * 服务器由于维护或者负载过重未能应答
     */
    SERVICE_UNAVAILABLE(503, "服务器未能应答"),

    /**
     * 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答
     */
    GATEWAY_TIMEOUT(504, "服务器未能应答"),

    /**
     * 未知错误
     */
    UNKNOWN(1000, "未知错误"),

    /**
     * 解析错误
     */
    PARSE_ERROR(1001, "解析错误"),

    /**
     * 网络错误
     */
    NETWORD_ERROR(1002, "网络异常,请尝试刷新"),

    /**
     * 协议出错
     */
    HTTP_ERROR(1003, "404 Not Found"),

    /**
     * 证书出错
     */
    SSL_ERROR(1004, "证书出错"),

    /**
     * 连接超时
     */
    TIMEOUT_ERROR(1006, "连接超时"),

    /**
     * 未登录
     */
    UNLOGIN(-1001, "未登录"),

    /**
     * 未知Host
     */
    UNKNOW_HOST(1007, "未知Host");
}

/**
 * 统一错误处理工具类
 */
object ExceptionHandler {

    fun handleException(e: Throwable): ApiException {

        val ex: ApiException
        if (e is ApiException) {
            ex = ApiException(e.errCode, e.errMsg, e)
            if (ex.errCode == ERROR.UNLOGIN.code){
                //登录失效
            }
        } else if (e is NoNetWorkException) {
            TipsToast.showTips("网络异常,请尝试刷新")
            ex = ApiException(ERROR.NETWORD_ERROR, e)
        } else if (e is HttpException) {
            ex = when (e.code()) {
                ERROR.UNAUTHORIZED.code -> ApiException(ERROR.UNAUTHORIZED, e)
                ERROR.FORBIDDEN.code -> ApiException(ERROR.FORBIDDEN, e)
                ERROR.NOT_FOUND.code -> ApiException(ERROR.NOT_FOUND, e)
                ERROR.REQUEST_TIMEOUT.code -> ApiException(ERROR.REQUEST_TIMEOUT, e)
                ERROR.GATEWAY_TIMEOUT.code -> ApiException(ERROR.GATEWAY_TIMEOUT, e)
                ERROR.INTERNAL_SERVER_ERROR.code -> ApiException(ERROR.INTERNAL_SERVER_ERROR, e)
                ERROR.BAD_GATEWAY.code -> ApiException(ERROR.BAD_GATEWAY, e)
                ERROR.SERVICE_UNAVAILABLE.code -> ApiException(ERROR.SERVICE_UNAVAILABLE, e)
                else -> ApiException(e.code(), e.message(), e)
            }
        } else if (e is JsonParseException
                || e is JSONException
                || e is ParseException
                || e is MalformedJsonException
        ) {
            ex = ApiException(ERROR.PARSE_ERROR, e)
        } else if (e is ConnectException) {
            ex = ApiException(ERROR.NETWORD_ERROR, e)
        } else if (e is javax.net.ssl.SSLException) {
            ex = ApiException(ERROR.SSL_ERROR, e)
        } else if (e is java.net.SocketException) {
            ex = ApiException(ERROR.TIMEOUT_ERROR, e)
        } else if (e is java.net.SocketTimeoutException) {
            ex = ApiException(ERROR.TIMEOUT_ERROR, e)
        } else if (e is java.net.UnknownHostException) {
            ex = ApiException(ERROR.UNKNOW_HOST, e)
        } else {
            ex = if (!e.message.isNullOrEmpty()) ApiException(1000, e.message!!, e)
            else ApiException(ERROR.UNKNOWN, e)
        }
        return ex
    }
}


以上直接复制过去就能用,非常好用。

下面代码是调用。一行代码搞定,很愉快就调用了,而且还好理解,方便接手的人维护。不像有些博主写的框架,调用一层套一层,搞到后面接手的人很懵逼。

     lifecycleScope.launch {


                loadHttp(start = {
                    LoadingView.getInstance(this@SplashActivity).showPopupWindow()
                },
                    request = {
                       RetrofitBuilder.create<Api>(Api.BASE_URL).getBannerJson()
                    },
                    end = {
                        LoadingView.getInstance(this@SplashActivity).dismiss()
                    }).fold({
                    Loge.e(it.toString())
                }, {
                    val exception = ExceptionHandler.handleException(it)
                    Loge.e(exception.errMsg + ":" + exception.errCode)
                })

            }

或者这样直接调用: 一行简洁代码搞定。

loadHttp{
      RetrofitBuilder.create<Api>(Api.BASE_URL).getBannerJson()
}.onSuccess {
//请求成功处理
      banner.value = it
}.onFailure { 
//请求失败处理
      val exception = ExceptionHandler.handleException(it)
      Loge.e(exception.errMsg + ":" + exception.errCode)
 }

最后做个补充,直接取消协程就会自动取消网络请求了。

 val job = lifecycleScope.launch {
                loadHttp {
                 RetrofitBuilder.create<Api>(Api.BASE_URL).getBannerJson()
                }
            }
            job.cancel()//协程取消网络请求直接会取消、
            或者使用 lifecycleScope.cancel()
当然,也可以直接取消lifecycleScope 来统一取消所有的网络请求,其他的viewModelScope等 同理
viewModelScope.cancel()

使用kotlin 谷歌内置了很多有用的高阶函数可以让代码更加简洁,

suspend fun <T> loadHttp2(  //可以通过取消协程的方法来取消网络请求。比如使用lifecycleScope请求网络,当lifecycleScope取消的时候,网络请求同时取消了
    timeout: Long = 10000,
    request: suspend () -> BaseResponse<T>
): Result<T> {
    // 在主线程(Dispatchers.Main)执行

    return kotlin.runCatching {
        var data: T = "" as T
        val response = withTimeout(timeout) {
            request()
        }
        if (response.errorCode == 0) {
            if (response.data == null) data = "" as T else data = response.data
        }
        data
    }

}

调用loadhttp2

   job = lifecycleScope.launch {

                loadHttp2 {
                    RetrofitFactory.instance.service.getBannerJson()
                }.onSuccess {
                    Loge.e(it.toString())
                }.onFailure {
                    val apiException = ExceptionHandler.handleException(it)
                    Loge.e(apiException.errMsg + ":" + apiException.errCode)
                }
            }
job.cancel //(取消网络请求)

分享几个好用缓存处理的拦截器。

  //网络状态拦截
        build.addInterceptor(object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                if (NetworkUtil.isConnected(SumAppHelper.getApplication())) {
                    val request = chain.request()
                    return chain.proceed(request)
                } else {
                    throw NoNetWorkException(ERROR.NETWORD_ERROR)
                }
            }
        })


//        build.addNetworkInterceptor { chain ->
//
//            val request = chain.request();
//            val response = chain.proceed(request);
//
//            var cacheControl = request.cacheControl().toString();
//            if (TextUtils.isEmpty(cacheControl)) {
//                cacheControl = "public, max-age=60";
//            }
//            return@addNetworkInterceptor response.newBuilder()
//                .header("Cache-Control", cacheControl)
//                .removeHeader("Pragma")
//                .build();
//
//
//        }
        build.addInterceptor { chain ->

            var request = chain.request();
            if (!NetworkUtil.isConnected(SumAppHelper.getApplication())) {
                val offlineCacheTime = 6000;//离线的时候的缓存的过期时间
                request = request.newBuilder()
//                        .cacheControl(new CacheControl
//                                .Builder()
//                                .maxStale(60,TimeUnit.SECONDS)
//                                .onlyIfCached()
//                                .build()
//                        ) 两种方式结果是一样的,写法不同
                    .header(
                        "Cache-Control",
                        "public, only-if-cached, max-stale=" + offlineCacheTime
                    )
                    .build();
            }
            return@addInterceptor chain.proceed(request);
        }

        build.addNetworkInterceptor { chain ->
            val request = chain.request();
            val response = chain.proceed(request);
            val onlineCacheTime = 60;//在线的时候的缓存过期时间,如果想要不缓存,直接时间设置为0
            return@addNetworkInterceptor response.newBuilder()
                .header("Cache-Control", "public, max-age=" + onlineCacheTime)
                .removeHeader("Pragma")
                .build()
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值