Android的網絡請求之OkHttp封裝


OkHttp的封裝

市面上每個人都有自己IDE網絡請求封裝,比如OKGo、OkHttpUtil、NoHttp都是很不錯的國內開發者封裝的框架,我封裝的更多的是自己隨心而為之。主要的一個點是將Request的封裝和解析更加自由。
使用的步驟如下

  1. 依賴相關的OkHttp的庫,我這里依賴的是3.14.9,因為4.X以上開始支持kotlin啦,書寫方式有些許不一樣
  2. 依賴GSON庫,用於json對象的解析
  3. 你的數據基礎對象實現Result
  4. 封裝好你自己的網絡Request,然后在調用OkHttpUtil.getInstance().syncRequest()/asyncRequest()/downAsync(),來調用同步、異步、下載文件的方法

具體的內容如下

  1. 配置類HttpConfig.kt
data class HttpConfig(
    val connectTimeout: Long = 10L,//網絡連接時間
    val writeTimeout: Long = 20L,//網絡連接時間
    val readTimeout: Long = 20L,//網絡讀取時間
    var interceptors: List<Interceptor>? = emptyList(),//自定義攔截器
) {
    var cacheDir: File? = null//緩存的文件夾
    var cacheSize: Long = 10 * 1024 * 1024//緩存的文件夾大小
    var isSupportCookie = false//是否支持cookie
    var sslSocketFactory: SSLSocketFactory? = null
    var trustManager: X509TrustManager? = null
    var printLog = false//默認打印日志
}
  1. 定義網絡的請求回調ResultCallback.kt
abstract class ResultCallback<T> {
    companion object {
        val handler = Handler(Looper.getMainLooper())
    }

    /**
     * 網絡請求開始的時候  可以用於彈窗的處理等
     */
    fun onHandleStart() {
        handler.post {
            onStart()
        }
    }

    /**
     * 訪問網絡失敗后被調用
     */
    fun onHandleFailure(call: Call?, exception: Exception?) {
        handler.post {
            onFailure(call = call, exception = exception)
            onFinish()
        }
    }

    /**
     * 用於回調的處理
     */
    fun onResponse(call: Call?, response: Response) {
        val parseResult = onHandleResponse(call, response)
        handler.post {
            parseResult?.let {
                onSuccess(call = call, response = it as T)
            } ?: onFailure(call = call, NullPointerException())
            onFinish()
        }
    }

    /**
     * 下載的進度監聽 執行在子線程
     *
     * @param byteRead 已讀長度
     * @param total    總長度
     */
    fun onHandleProgress(byteRead: Long, total: Long) {
        handler.post {
            onProgress(byteRead, total)
        }
    }

    /**
     * 網絡請求開始的時候  可以用於彈窗的處理等
     */
   open abstract fun onStart()

    /**
     * 失敗返回的數據,執行在UI線程
     */
    open abstract fun onFailure(call: Call?, exception: Exception?)

    /**
     * 解析response,執行在子線程
     */
    open abstract fun onHandleResponse(call: Call?, response: Response?): T?

    /**
     * 下載的進度監聽  執行在UI線程
     *
     * @param byteRead 已讀長度
     * @param total    總長度
     */
    open abstract fun onProgress(byteRead: Long, total: Long)

    /**
     * 成功返回的數據,執行在UI線程
     */
    abstract fun onSuccess(call: Call?, response: T)

    /**
     * 網絡請求結束 執行在UI線程
     */
    abstract fun onFinish()
}
  1. OkHttp的單列OkHttpUtil.kt
class OkHttpUtil(httpConfig: HttpConfig?) {
    val httpClient: OkHttpClient?

    init {
        val config: HttpConfig = (httpConfig ?: HttpConfig())

        val builder = OkHttpClient.Builder()
        config.apply {
            builder.connectTimeout(connectTimeout, TimeUnit.SECONDS)
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
            cacheDir?.let {
                builder.cache(Cache(it, cacheSize))
            }
            // 添加一個請求攔截器
            val interceptors = interceptors
            if (interceptors != null && interceptors.isNotEmpty()) {
                for (interceptor in interceptors) {
                    builder.addInterceptor(interceptor)
                }
            }
            //安全證書
            sslSocketFactory?.also { sslSocketFactory ->
                trustManager?.also { trustManager ->
                    builder.sslSocketFactory(sslSocketFactory, trustManager)
                }
            }
            if (isSupportCookie) {
                builder.cookieJar(object : CookieJar {
                    private val cookieStore = HashMap<HttpUrl, List<Cookie>>()
                    override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
                        cookieStore[url] = cookies
                    }

                    override fun loadForRequest(url: HttpUrl): List<Cookie> {
                        val cookies = cookieStore[url]
                        return cookies ?: ArrayList()
                    }
                })
            }
        }
        httpClient = builder.build()
    }

    /**
     * 同步請求
     *
     * @param request
     */
    @Throws(IOException::class)
    fun syncRequest(request: Request): Response? {
        return httpClient?.newCall(request)?.execute()
    }

    /**
     * 異步請求
     *
     * @param request
     * @param callback
     * @param <T>
    </T> */
    fun <T> asyncRequest(request: Request, callback: ResultCallback<Any>?) {
        if (httpClient == null) {
            return
        }
        callback?.onHandleStart()
        httpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback?.onHandleFailure(call, e)
            }

            override fun onResponse(call: Call, response: Response) {
                callback?.onResponse(call, response)
            }
        })
    }

    /**
     * 下載文件並提供出進度監聽
     *
     * @param url 地址
     * @param callback 回調
     */
    fun downAsync(
        url: String,
        tag: String?,
        callback: DownloadCallback?,
    ) {
        if (httpClient == null || callback == null) {
            return
        }
        val parentFile = callback.destFile.parentFile ?: return
        if (!parentFile.exists()) {
            parentFile.mkdirs()
        }
        callback.onHandleStart()
        val request: Request = Request.Builder()
            .tag(tag?.let { tag } ?: url)
            .url(url)
            .build()
        httpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback.onHandleFailure(call, e)
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                callback.onResponse(call, response)
            }
        })
    }

    /**
     * 全部隊列中請求全部取消
     */
    fun cancelAll() {
        httpClient?.dispatcher?.cancelAll()
    }

    /**
     * call 取消
     *
     * @param call
     */
    fun cancel(call: Call?) {
        call?.cancel()
    }

    /**
     * 根據標記取消請求的隊列和排隊中的隊列
     *
     * @param tag
     */
    fun cancel(tag: String) {
        if (null != httpClient) {
            val dispatcher = httpClient.dispatcher
            cancelCall(dispatcher.runningCalls(), tag)
            cancelCall(dispatcher.queuedCalls(), tag)
        }
    }

    private fun cancelCall(callList: List<Call>?, tag: String) {
        callList?.let { callList ->
            callList.filter { it.request().tag() == tag }.forEach { call ->
                call.cancel()
            }
        }
    }
}
  1. [進階版]RetrofitUti.kt 使用Retrofit+OkHttp
class RetrofitUtil {
    private val retrofitMap = ConcurrentHashMap<String, Any?>()
    open fun <T> createService(baseUrl: String, client: OkHttpClient, tClass: Class<T>): T? {
        var service = retrofitMap[baseUrl] as T?
        if (null == service) {
            service = Retrofit.Builder()
                .client(client)
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build().create(tClass)
            retrofitMap[baseUrl] = service
        }
        return service
    }

    /**
     * 處理請求層的錯誤,對可能的已知的錯誤進行處理
     */
    private fun handleExceptions(e: Throwable): String {
        e.printStackTrace()
        return when (e) {
            is CancellationException -> "請求取消"
            is SocketTimeoutException -> "連接超時"
            is JsonParseException -> "數據解析錯誤"
            is NumberFormatException -> "數據類型轉換錯誤"
            else -> "請求失敗,請稍后再試"
        }
    }
}
  1. [高階版] Retrofit+OkHttp+RxJava
public interface Result<T> {
    boolean extSuccess();//項目中返回成功的字段,有的是T,有的是Y,有的是200,有的是0等,可以自定義此狀態
    T extBody();//返回結果
}

public abstract class SimpleObserver<T> implements SingleObserver<Result<T>>, LifecycleObserver {
    private Lifecycle mLifecycle;
    private Disposable mDisposable;

    public SimpleObserver(Lifecycle lifecycle) {
        mLifecycle = lifecycle;
    }

    @Override
    public void onSubscribe(Disposable disposable) {
        mDisposable = disposable;
        if (mLifecycle != null) {
            mLifecycle.addObserver(this);
        }
        onStart();
    }

    @Override
    public void onSuccess(Result<T> tResult) {
        if (null == tResult || !tResult.extSuccess()) {
            onFailure(404, "服務器異常,請稍后嘗試");
        } else {
            if (tResult.extSuccess()) {
                onResult(tResult.extBody());
            }
        }
        onFinish();
    }

    @Override
    public void onError(Throwable throwable) {
        if (isNetError(throwable)) {
            if (throwable instanceof SocketTimeoutException) {
                onFailure(500, "請求超時,請檢查網絡");
            } else {
                onFailure(500, "您的網絡好像有問題,請檢查網絡");
            }
        } else {
            onFailure(404, "服務器異常,請稍后嘗試");
        }
        onFinish();
    }

    /**
     * 網絡請求開始
     */
    public abstract void onStart();

    /**
     * 網絡請求返回的對象
     *
     * @param result 結果對象
     */
    public abstract void onResult(T result);

    /**
     * 請求失敗
     *
     * @param errorCode    錯誤碼
     * @param errorMessage 錯誤信息
     */
    public abstract void onFailure(int errorCode, String errorMessage);

    public void onFinish() {
        //解除與lifecycle的綁定。
        if (mLifecycle != null) {
            mLifecycle.removeObserver(this);
        }
        //動釋放
        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
    }

    private static boolean isNetError(Throwable throwable) {
        return throwable instanceof HttpException || throwable instanceof SocketTimeoutException ||
                throwable instanceof ConnectException || throwable instanceof UnknownHostException;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM