OKHttp 核心知識點詳解
一、基本概念與架構
1. OKHttp 簡介
- 類型:高效的HTTP客戶端
- 特點:
- 支持HTTP/2和SPDY(多路復用)
- 連接池減少請求延遲
- 透明的GZIP壓縮
- 響應緩存
- 自動恢復網絡故障
2. 核心組件
組件 | 功能 |
---|---|
OkHttpClient | 客戶端入口,配置中心 |
Request | 封裝請求信息 |
Response | 封裝響應信息 |
Call | 執行請求的接口 |
Interceptor | 攔截器鏈處理請求/響應 |
二、基礎使用
1. 添加依賴
implementation("com.squareup.okhttp3:okhttp:4.10.0") // 最新穩定版
2. 同步請求
val client = OkHttpClient()
val request = Request.Builder().url("https://api.example.com/data").build()try {val response = client.newCall(request).execute()if (response.isSuccessful) {val responseData = response.body?.string()}
} catch (e: IOException) {e.printStackTrace()
}
3. 異步請求
val request = Request.Builder().url("https://api.example.com/data").build()client.newCall(request).enqueue(object : Callback {override fun onResponse(call: Call, response: Response) {val responseData = response.body?.string()}override fun onFailure(call: Call, e: IOException) {e.printStackTrace()}
})
三、高級功能
1. 攔截器(Interceptors)
應用攔截器(Application Interceptors)
val client = OkHttpClient.Builder().addInterceptor(LoggingInterceptor()).build()class LoggingInterceptor : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {val request = chain.request()// 請求前日志Log.d("OKHttp", "Sending request: ${request.url}")val response = chain.proceed(request)// 響應后日志Log.d("OKHttp", "Received response: ${response.code}")return response}
}
網絡攔截器(Network Interceptors)
.addNetworkInterceptor(StethoInterceptor()) // Facebook調試工具
2. 緩存配置
val cacheSize = 10 * 1024 * 1024 // 10MB
val cache = Cache(File(context.cacheDir, "http_cache"), cacheSize)val client = OkHttpClient.Builder().cache(cache).addInterceptor(CacheInterceptor()).build()class CacheInterceptor : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {val request = chain.request()val response = chain.proceed(request)val cacheControl = CacheControl.Builder().maxAge(30, TimeUnit.MINUTES).build()return response.newBuilder().header("Cache-Control", cacheControl.toString()).build()}
}
3. 超時設置
val client = OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS) // 連接超時.readTimeout(15, TimeUnit.SECONDS) // 讀取超時.writeTimeout(15, TimeUnit.SECONDS) // 寫入超時.callTimeout(30, TimeUnit.SECONDS) // 整個調用超時.build()
四、請求定制
1. 請求頭設置
val request = Request.Builder().url("https://api.example.com/data").header("Authorization", "Bearer token123").addHeader("Accept", "application/json").build()
2. 表單提交
val formBody = FormBody.Builder().add("username", "admin").add("password", "123456").build()val request = Request.Builder().url("https://api.example.com/login").post(formBody).build()
3. 文件上傳
val file = File("/sdcard/image.jpg")
val requestBody = MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("file", file.name,file.asRequestBody("image/jpeg".toMediaType())).addFormDataPart("description", "A cool image").build()val request = Request.Builder().url("https://api.example.com/upload").post(requestBody).build()
4. JSON 數據提交
val json = """{"name": "John","age": 30}
""".trimIndent()val requestBody = json.toRequestBody("application/json".toMediaType())val request = Request.Builder().url("https://api.example.com/users").post(requestBody).build()
五、響應處理
1. 響應頭讀取
val response = client.newCall(request).execute()
val contentType = response.header("Content-Type")
val allHeaders = response.headers
2. 響應體處理
// 字符串形式
val stringBody = response.body?.string()// 字節流形式
val bytes = response.body?.bytes()// 流式處理
response.body?.source()?.use { source ->while (!source.exhausted()) {val buffer = source.buffer()// 處理buffer}
}
六、高級配置
1. 連接池配置
val client = OkHttpClient.Builder().connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES)).build()
2. 代理設置
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("proxy.example.com", 8080))
val client = OkHttpClient.Builder().proxy(proxy).build()
3. 證書鎖定(Certificate Pinning)
val certificatePinner = CertificatePinner.Builder().add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=").build()val client = OkHttpClient.Builder().certificatePinner(certificatePinner).build()
4. 自定義DNS
val dns = Dns { hostname ->if (hostname == "api.example.com") {listOf(InetAddress.getByName("1.2.3.4"))} else {Dns.SYSTEM.lookup(hostname)}
}val client = OkHttpClient.Builder().dns(dns).build()
七、WebSocket 支持
val request = Request.Builder().url("wss://echo.websocket.org").build()val listener = object : WebSocketListener() {override fun onOpen(webSocket: WebSocket, response: Response) {webSocket.send("Hello!")}override fun onMessage(webSocket: WebSocket, text: String) {println("Received: $text")}override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {println("Closed: $reason")}override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {t.printStackTrace()}
}val webSocket = client.newWebSocket(request, listener)// 關閉連接
webSocket.close(1000, "Goodbye!")
八、常見問題解決方案
1. 內存泄漏問題
// 在Activity/Fragment銷毀時取消請求
private val calls = mutableListOf<Call>()override fun onDestroy() {super.onDestroy()calls.forEach { it.cancel() }
}// 發起請求時保存Call對象
val call = client.newCall(request)
calls.add(call)
call.enqueue(object : Callback {override fun onResponse(call: Call, response: Response) {calls.remove(call)// 處理響應}override fun onFailure(call: Call, e: IOException) {calls.remove(call)// 處理錯誤}
})
2. 大文件下載進度監聽
val request = Request.Builder().url("https://example.com/largefile.zip").build()client.newCall(request).enqueue(object : Callback {override fun onResponse(call: Call, response: Response) {response.body?.let { body ->val inputStream = body.byteStream()val contentLength = body.contentLength()var bytesRead: Long = 0val buffer = ByteArray(8192)FileOutputStream(localFile).use { output ->var read = inputStream.read(buffer)while (read != -1) {output.write(buffer, 0, read)bytesRead += readval progress = (bytesRead * 100 / contentLength).toInt()updateProgress(progress) // 更新UIread = inputStream.read(buffer)}}}}override fun onFailure(call: Call, e: IOException) {// 處理錯誤}
})
3. 請求重試機制
val client = OkHttpClient.Builder().addInterceptor(RetryInterceptor(maxRetries = 3)).build()class RetryInterceptor(private val maxRetries: Int) : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {val request = chain.request()var response: Response? = nullvar exception: IOException? = nullfor (i in 0..maxRetries) {try {response = chain.proceed(request)if (response.isSuccessful) {return response}} catch (e: IOException) {exception = e}if (i < maxRetries) {Thread.sleep(1000L * (i + 1)) // 指數退避}}throw exception ?: IOException("Unknown error")}
}
九、最佳實踐
- 單例模式:推薦將
OkHttpClient
實例作為單例使用 - 資源釋放:確保關閉
Response
和ResponseBody
- 線程安全:
OkHttpClient
是線程安全的,可共享使用 - 性能優化:
- 合理設置連接池大小
- 使用緩存減少網絡請求
- 壓縮請求數據
- 錯誤處理:
- 處理各種IO異常
- 檢查響應碼(
response.isSuccessful
) - 考慮網絡不可用情況
OKHttp 是 Android 開發中最強大、靈活的 HTTP 客戶端之一,掌握其核心功能可以顯著提升應用的網絡性能和穩定性。