版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
OkHttp
OkHttp 是一个高效的 HTTP 客户端库,由 Square 公司开发,广泛应用于 Android 开发中。它支持同步和异步请求、连接池、压缩、缓存、拦截器等高级特性,是 Android 网络请求的主流选择之一。
开源地址:https://github.com/square/okhttp
OkHttp 的核心特点:
-
支持 HTTP/1.1 和 HTTP/2
-
自动连接重用与请求队列复用
-
支持透明的 GZIP 压缩
-
支持缓存响应数据以减少重复请求
-
支持自定义拦截器(用于日志、请求修改、认证等)
-
异步请求基于线程池,不阻塞主线程
在 Android Studio 中使用 OkHttp
在 build.gradle(:app) 中加入 OkHttp 的依赖项:
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
可选:日志拦截器(用于打印请求和响应)
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
Kotlin 封装的 OkHttpClient 单例
功能说明:
-
单例模式(线程安全)
-
可选注册日志拦截器
-
封装常用请求方法:GET、POST(JSON / 表单)、PUT、DELETE
-
支持 全局请求头(如 Authorization Token)
-
支持 协程版 suspend 函数(适合 ViewModelScope 等使用)
-
支持 文件上传 Multipart 请求
-
保留原有 Callback 异步接口(兼容老代码)
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.Headers.Companion.toHeaders
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit
object NetworkClient {
private var loggingEnabled = false
private val JSON = "application/json; charset=utf-8".toMediaType()
private val FORM = "application/x-www-form-urlencoded".toMediaType()
private var globalHeaders: MutableMap<String, String> = mutableMapOf()
private val client: OkHttpClient by lazy {
val builder = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
if (loggingEnabled) {
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
builder.addInterceptor(logging)
}
builder.build()
}
// 启用日志拦截器(必须在首次请求前调用)
fun enableLogging() {
loggingEnabled = true
}
// 设置全局请求头(如 token)
fun setGlobalHeader(key: String, value: String) {
globalHeaders[key] = value
}
fun clearGlobalHeaders() {
globalHeaders.clear()
}
private fun buildHeaders(custom: Map<String, String>? = null): Headers {
val all = globalHeaders.toMutableMap()
custom?.let { all.putAll(it) }
return all.toHeaders()
}
// ========= 协程版本(推荐) =========
suspend fun getSuspend(url: String, headers: Map<String, String>? = null): String =
withContext(Dispatchers.IO) {
val request = Request.Builder()
.url(url)
.headers(buildHeaders(headers))
.get()
.build()
client.newCall(request).execute().use {
if (!it.isSuccessful) throw IOException("Unexpected code $it")
it.body?.string() ?: ""
}
}
suspend fun postJsonSuspend(url: String, json: String, headers: Map<String, String>? = null): String =
withContext(Dispatchers.IO) {
val body = json.toRequestBody(JSON)
val request = Request.Builder()
.url(url)
.headers(buildHeaders(headers))
.post(body)
.build()
client.newCall(request).execute().use {
if (!it.isSuccessful) throw IOException("Unexpected code $it")
it.body?.string() ?: ""
}
}
suspend fun postFormSuspend(url: String, formData: Map<String, String>, headers: Map<String, String>? = null): String =
withContext(Dispatchers.IO) {
val formBody = FormBody.Builder().apply {
formData.forEach { (k, v) -> add(k, v) }
}.build()
val request = Request.Builder()
.url(url)
.headers(buildHeaders(headers))
.post(formBody)
.build()
client.newCall(request).execute().use {
if (!it.isSuccessful) throw IOException("Unexpected code $it")
it.body?.string() ?: ""
}
}
suspend fun uploadFileSuspend(
url: String,
file: File,
fileField: String = "file",
extraFormData: Map<String, String>? = null,
headers: Map<String, String>? = null
): String = withContext(Dispatchers.IO) {
val fileBody = file.asRequestBody("application/octet-stream".toMediaType())
val multipartBody = MultipartBody.Builder().setType(MultipartBody.FORM).apply {
addFormDataPart(fileField, file.name, fileBody)
extraFormData?.forEach { (k, v) -> addFormDataPart(k, v) }
}.build()
val request = Request.Builder()
.url(url)
.headers(buildHeaders(headers))
.post(multipartBody)
.build()
client.newCall(request).execute().use {
if (!it.isSuccessful) throw IOException("Upload failed: $it")
it.body?.string() ?: ""
}
}
// ========= 原始 Callback 异步版本(兼容旧代码) =========
fun get(url: String, headers: Map<String, String>? = null, callback: Callback) {
val request = Request.Builder()
.url(url)
.headers(buildHeaders(headers))
.get()
.build()
client.newCall(request).enqueue(callback)
}
fun postJson(url: String, json: String, headers: Map<String, String>? = null, callback: Callback) {
val body = json.toRequestBody(JSON)
val request = Request.Builder()
.url(url)
.headers(buildHeaders(headers))
.post(body)
.build()
client.newCal

最低0.47元/天 解锁文章
1057

被折叠的 条评论
为什么被折叠?



