OkHttp是一个用于Android和Java应用的高效HTTP客户端库。它具有以下优点:
优点
- 高效连接池 :
- 支持连接复用(Connection Pooling)减少延迟。
- 有效管理HTTP/2多路复用。
- 透明压缩 :
- 自动处理Gzip压缩,减少传输的数据量。
- 缓存响应 :
- 内置缓存机制,帮助减少不必要的网络调用,提高速度和节省流量。
- 异步请求 :
- 支持异步请求,避免阻塞主线程,提高应用响应速度。
- 支持WebSocket :
- 提供WebSocket支持,便于实时通信。
- 安全性 :
- 支持TLS加密,确保数据传输的安全性。
- 易于集成和使用 :
- 简单的API设计,方便与其他库(如Retrofit)集成。
简单使用
- 依赖
java
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation("com.google.code.gson:gson:2.8.8")
- 定义json转换的对象
kotlin
data class ImageData(
val createTime: Long,
val id: Long,
val name: String,
val path: String,
val size: Long
)
data class ApiResponse(
val data: List<ImageData>,
val errorCode: Int,
val isSuccess: Boolean
)
- 直接调用即可,主要在接收到后使用Gson反序列化。
kotlin
class OkHttpActivity : AppCompatActivity() {
private lateinit var binding: ActivityOkHttpBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityOkHttpBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
fetchData()
}
private fun fetchData() {
val client = OkHttpClient()
val request = Request.Builder()
.url("http://192.168.42.7:9876/image/listImage?page=0&pageSize=100")
.build()
client.newCall(request).enqueue(object : okhttp3.Callback {
override fun onFailure(call: okhttp3.Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
response.body?.string()?.let { jsonString ->
val apiResponse = Gson().fromJson(jsonString, ApiResponse::class.java)
runOnUiThread {
binding.recyclerView.adapter = ImageAdapter(apiResponse.data)
}
}
}
})
}
}
效果
拦截器
-
RetryAndFollowUpInterceptor:重试+重定向
- 直接放行,在调用后才会去执行
- 根据retryOnConnectionFailure属性、请求体类型判断是否重试
- 重试无次数限制,重定向20次
-
BridgeInterceptor
- 对用户请求进行预处理,添加必要的请求头信息,如Content-Type、Content-Length、Host、Connection、Accept-Encoding(如果用户未指定则添加gzip支持)、Cookie(如果有)和User-Agent(如果用户未指定)。
- 处理网络响应,包括处理透明的 gzip 压缩响应,解压 gzip 压缩的响应体并更新响应头,去除Content-Encoding和Content-Length头信息,并使用新的响应体。
- 负责将请求的 Cookie 发送到服务器,并接收服务器返回的 Cookie 更新本地的 CookieJar。
-
CacheInterceptor(只对get有效,需要配置cache)(DiskLruCache)
- 配置
javaval builder = OkHttpClient.Builder() builder.cache(Cache(File(""),1000))
-
ConnectInterceptor
- 建立与服务器的连接并初始化数据交换对象,然后继续沿着拦截器链执行后续的处理步骤。
- 得到一个链接后传给下一层(connectionPool)
-
CallServerInterceptor
- 负责将参数封装到request
- 将结果封装到response
- Expect: 100-continue,大容量请求或验证
原理
okhttp(传输层)
- Deque(双端队列)
等待队列
private val readyAsyncCalls = ArrayDeque()
异步队列
private val runningAsyncCalls = ArrayDeque()
同步队列
private val runningSyncCalls = ArrayDeque() - running队列数量<64,并且同时访问同一个host数量<5,就直接加入running队列,否则则加入等待队列
4.9.3版本:直接加入readyAsyncCalls队列,call.callsPerHost指向同一个AtomicInteger,原子计数。
maxRequests = 64,maxRequestsPerHost = 5在取出时考虑
kotlin
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)//PerHostFrom原子计数
}
}
promoteAndExecute()
}
- 基于第二点的控制,所以线程池不设置等待队列,使用SynchronousQueue无容量队列,且最大线程数无限,核心为0
kotlin
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
- 执行结束后移除队列,并执行回调
kotlin
private fun <T> finished(calls: Deque<T>, call: T) {
val idleCallback: Runnable?
synchronized(this) {
if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
idleCallback = this.idleCallback
}
val isRunning = promoteAndExecute()
if (!isRunning && idleCallback != null) {
idleCallback.run()
}
}
-
构建者模式,责任链模式
-
connectInteceptor创建socket请求
-
ConnectionPool,设置线程池为守护线程
- 避免阻止 JVM 正常退出。
- 更高效地管理后台任务和连接。
- 自动清理资源,防止资源泄漏。
-
promoteCalls执行下一个任务