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;
}
}