OkHttp的封裝
市面上每個人都有自己IDE網絡請求封裝,比如OKGo、OkHttpUtil、NoHttp都是很不錯的國內開發者封裝的框架,我封裝的更多的是自己隨心而為之。主要的一個點是將Request的封裝和解析更加自由。
使用的步驟如下
- 依賴相關的OkHttp的庫,我這里依賴的是3.14.9,因為4.X以上開始支持kotlin啦,書寫方式有些許不一樣
- 依賴GSON庫,用於json對象的解析
- 你的數據基礎對象實現Result
- 封裝好你自己的網絡Request,然后在調用OkHttpUtil.getInstance().syncRequest()/asyncRequest()/downAsync(),來調用同步、異步、下載文件的方法
具體的內容如下
- 配置類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//默認打印日志
}
- 定義網絡的請求回調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()
}
- 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()
}
}
}
}
- [進階版]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 -> "請求失敗,請稍后再試"
}
}
}
- [高階版] 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;
}
}