okhttp
31.pngokhttp 是一个高效的 HTTP 客户端,它的横空出世,让其他的网络请求框架都变得黯然失色。
背景
在 okhttp 出现以前,Android 发起网络请求要么使用系统自带的 HttpClient 、HtttpURLConnection ;要么使用 Google 开源的 Volley ; 要么使用第三方开源的 AsyncHttpClient 等等。
目前大量流行库都以 okhttp 作为底层网络请求框架或提供支持,比如:Retrofit、Glide、Fresco、Moshi、Picasso 等。
特点
- 同时支持 Http1.1 和 Http2.0
- 同时支持同步与异步请求;
- 同时具备 Http 与 WebSocket 功能;
- 拥有自动维护的 socket 连接池,减少握手次数;
- 拥有队列线程池,轻松写并发;
- 拥有 Interceptors(拦截器),轻松处理请求与响应额外需求。
开始使用
- 在 AndroidManifest.xml 中添加网络访问权限:
<uses-permission android:name="android.permission.INTERNET"/>
- 在 app/build.gradle 的 dependencies 中添加如下依赖:
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.3")
- 初始化
import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
/**
* Created on 2021/12/16 10:02
*
* @author Gong Youqiang
*/
object BaseOkHttp {
val client = OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.build()
}
GET 请求
同步 GET 请求
同步 GET 请求是指一直等待 http 请求,直到返回了响应。在这之间会阻塞线程,所以同步请求不能在 Android 的主线程中执行,否则会报 NetworkMainThreadException.
object BaseOkHttp {
private const val TAG = "BaseOkHttp"
// 1. 创建 OkHttpClient 实例 client
val client = OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.build()
fun get(url:String) {
Thread(Runnable {
// 2. 通过 Request.Builder() 构建一个 Request 请求实例 request
val request:Request = Request.Builder()
.url(url)
.build()
// 3. 通过 client.newCall(request) 创建一个 Call 实例
val call = client.newCall(request)
// 4. Call 的实例调用 execute 方法发送同步请求
val response = call.execute()
val body = response.body?.string()
// 5. 请求返回的 response 转换为 String 类型返回
Log.e(TAG,"get response : ${body}")
}).start()
}
}
异步 GET 请求
异步 GET 请求是指在另外的工作线程中执行 http 请求,请求时不会阻塞当前的线程,所以可以在 Android 主线程中使用。
/**
* Created on 2021/12/16 10:02
*
* @author Gong Youqiang
*/
object BaseOkHttp {
private const val TAG = "BaseOkHttp"
val client = OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.build()
fun getAsync(url:String) {
// 构造请求体
val request:Request = Request.Builder()
.url(url)
.build()
// 构造请求对象
val call = client.newCall(request)
// 发起异步请求 enqueue
call.enqueue(object :Callback{
override fun onResponse(call: Call, response: Response) {
val body = response.body?.string()
Log.e(TAG,"get response : ${body}")
}
override fun onFailure(call: Call, e: IOException) {
Log.e(TAG,"get response failure : ${e.message}")
}
})
}
}
说明:无论是同步还是异步请求,接收到的 response 结果都是在子线程中,onResponse、onFailure 的回调是在子线程中的,我们需要切换到主线程才能操作 UI 控件。
POST 请求
同步 POST 请求
/**
* Created on 2021/12/16 10:02
*
* @author Gong Youqiang
*/
object BaseOkHttp {
// 注意该URL 是笔者本地服务器地址
private const val BASE_URL = "http://192.168.10.62:8082/HKservice"
private const val TAG = "BaseOkHttp"
val client = OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.build()
fun post() {
val body:FormBody = FormBody.Builder()
.add("id","35")
.add("status","进行中")
.build()
val request = Request.Builder()
.url("$BASE_URL/record/updateStatus")
.post(body)
.build()
val call = client.newCall(request)
Thread(Runnable {
val response = call.execute()
Log.e(TAG, "post response:${response.body?.string()}")
}).start()
}
}
异步 POST 请求
/**
* Created on 2021/12/16 10:02
*
* @author Gong Youqiang
*/
object BaseOkHttp {
// 注意该URL 是笔者本地服务器地址
private const val BASE_URL = "http://192.168.10.62:8082/HKservice"
private const val TAG = "BaseOkHttp"
val client = OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.build()
fun postAsync() {
val body:FormBody = FormBody.Builder()
.add("id","35")
.add("status","进行中")
.build()
val request = Request.Builder()
.url("$BASE_URL/record/updateStatus")
.post(body)
.build()
val call = client.newCall(request)
call.enqueue(object : Callback{
override fun onResponse(call: Call, response: Response) {
Log.e(TAG, "post response:${response.body?.string()}")
}
override fun onFailure(call: Call, e: IOException) {
Log.e(TAG, "post failure:${e.message}")
}
})
}
}
拦截器 LoggingInterceptor
作用
它是 OkHttp 中一个比较强大的机制,可以监视、重写和重试调用请求。
简单使用(自定义)
/**
* Created on 2021/12/16 13:38
*
* @author Gong Youqiang
*/
class LoggingInterceptor : Interceptor {
private val TAG = "OkHttp"
override fun intercept(chain: Interceptor.Chain): Response {
val time_start = System.nanoTime()
val request = chain.request()
val response = chain.proceed(request)
val buffer = Buffer()
request.body?.writeTo(buffer)
val requestBodyStr = buffer.readUtf8()
Log.e(TAG, String.format("Sending request %s with params %s",request.url,requestBodyStr))
val bussinessData = response.body?.string()?:"response body null"
val mediaType = response.body?.contentType()
val newBody = ResponseBody.create(mediaType,bussinessData)
val newResponse = response.newBuilder().body(newBody).build()
val time_end = System.nanoTime()
Log.e(TAG, String.format(
"Received response for %s in %.1ms >>> %s",
request.url,
(time_end - time_start) / 1e6,
bussinessData
))
return newResponse
}
}
使用自带的
/**
* Created on 2021/12/16 10:02
*
* @author Gong Youqiang
*/
object BaseOkHttp {
private const val BASE_URL = "http://192.168.10.62:8082/HKservice"
private const val TAG = "BaseOkHttp"
private val client:OkHttpClient
init {
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
client = OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.addInterceptor(httpLoggingInterceptor)
.build()
}
fun get(url:String) {
Thread(Runnable {
// 构造请求体
val request:Request = Request.Builder()
.url(url)
.build()
// 构造请求对象
val call = client.newCall(request)
// 发起同步请求 execute
val response = call.execute()
val body = response.body?.string()
Log.e(TAG,"get response : ${body}")
}).start()
}
}
网友评论