在Android开发中,Retrofit和OkHttp是网络请求的核心库。以下是如何高效封装它们的详细步骤:
一、基础封装方案
1. 添加依赖
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
2. OkHttp封装
object OkHttpManager {
private const val CACHE_SIZE = 10 * 1024 * 1024L // 10MB
private var okHttpClient: OkHttpClient? = null
fun getClient(context: Context): OkHttpClient {
return okHttpClient ?: createClient(context).also { okHttpClient = it }
}
private fun createClient(context: Context): OkHttpClient {
val cache = Cache(File(context.cacheDir, "http_cache"), CACHE_SIZE)
return OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.cache(cache)
.addInterceptor(LoggingInterceptor())
.addInterceptor(AuthInterceptor())
.addNetworkInterceptor(CacheInterceptor())
.build()
}
}
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
// 日志输出逻辑
return chain.proceed(request)
}
}
class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer ${getToken()}")
.build()
return chain.proceed(request)
}
}
class CacheInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
if (!isNetworkAvailable()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build()
}
return chain.proceed(request).newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=${60 * 60}")
.build()
}
}
3. Retrofit封装
object RetrofitManager {
private val retrofitMap = mutableMapOf<String, Retrofit>()
fun <T> createService(
context: Context,
serviceClass: Class<T>,
baseUrl: String = BASE_URL
): T {
val retrofit = retrofitMap[baseUrl] ?: buildRetrofit(context, baseUrl)
return retrofit.create(serviceClass)
}
private fun buildRetrofit(context: Context, baseUrl: String): Retrofit {
return Retrofit.Builder()
.baseUrl(baseUrl)
.client(OkHttpManager.getClient(context))
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
.also { retrofitMap[baseUrl] = it }
}
}
4. API Service定义
interface UserService {
@GET("users/{id}")
suspend fun getUser(@Path("id") userId: String): Response<User>
@POST("users")
suspend fun createUser(@Body user: User): Response<BaseResponse>
}
二、高级封装技巧
1. 统一响应处理
sealed class ApiResult<out T> {
data class Success<out T>(val data: T) : ApiResult<T>()
data class Error(val code: Int, val message: String?) : ApiResult<Nothing>()
object NetworkError : ApiResult<Nothing>()
}
suspend fun <T> safeApiCall(block: suspend () -> Response<T>): ApiResult<T> {
return try {
val response = block()
if (response.isSuccessful) {
ApiResult.Success(response.body()!!)
} else {
ApiResult.Error(response.code(), response.message())
}
} catch (e: IOException) {
ApiResult.NetworkError
} catch (e: Exception) {
ApiResult.Error(-1, e.message)
}
}
2. Repository层封装
class UserRepository {
private val service = RetrofitManager.createService(
context = App.context,
serviceClass = UserService::class.java
)
suspend fun getUser(userId: String): ApiResult<User> {
return safeApiCall { service.getUser(userId) }
}
}
3. ViewModel集成
class UserViewModel : ViewModel() {
private val repository = UserRepository()
private val _userData = MutableStateFlow<ApiResult<User>>(ApiResult.Success(null))
val userData: StateFlow<ApiResult<User>> = _userData
fun fetchUser(userId: String) {
viewModelScope.launch {
_userData.value = repository.getUser(userId)
}
}
}
三、关键配置项
- 多域名管理:
object ApiConfig {
const val MAIN_API = "https://api.main.com/"
const val PAYMENT_API = "https://api.payment.com/"
}
// 使用方式
val paymentService = RetrofitManager.createService(
context,
PaymentService::class.java,
ApiConfig.PAYMENT_API
)
- 动态Header处理:
class DynamicHeadersInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
val requestBuilder = original.newBuilder()
.header("App-Version", BuildConfig.VERSION_NAME)
.header("Device-Type", "Android")
// 动态添加token
getAuthToken()?.let {
requestBuilder.header("Authorization", "Bearer $it")
}
return chain.proceed(requestBuilder.build())
}
}
- 文件上传下载:
interface FileService {
@Multipart
@POST("upload")
suspend fun uploadFile(@Part file: MultipartBody.Part): Response<UploadResponse>
@Streaming
@GET("files/{filename}")
suspend fun downloadFile(@Path("filename") name: String): Response<ResponseBody>
}
四、调试技巧
- Stetho集成:
implementation 'com.facebook.stetho:stetho-okhttp3:1.6.0'
OkHttpClient.Builder()
.addNetworkInterceptor(StethoInterceptor())
.build()
- Mock数据调试:
val mockClient = OkHttpClient.Builder()
.addInterceptor(MockInterceptor())
.build()
class MockInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
return when (chain.request().url.pathSegments.last()) {
"users" -> mockUsersResponse()
else -> chain.proceed(chain.request())
}
}
}
五、性能优化建议
- 连接池配置:
val connectionPool = ConnectionPool(
maxIdleConnections = 5,
keepAliveDuration = 5,
timeUnit = TimeUnit.MINUTES
)
OkHttpClient.Builder()
.connectionPool(connectionPool)
- DNS优化:
class CustomDns : Dns {
override fun lookup(hostname: String): List<InetAddress> {
return try {
Dns.SYSTEM.lookup(hostname)
} catch (e: Exception) {
InetAddress.getAllByName(hostname).toList()
}
}
}
- 响应缓存策略:
val cacheControl = CacheControl.Builder()
.maxAge(2, TimeUnit.HOURS)
.maxStale(3, TimeUnit.DAYS)
.build()
request.newBuilder()
.cacheControl(cacheControl)
.build()
这种封装方案提供了以下优势:
- 统一的网络配置管理
- 完善的错误处理机制
- 支持协程和响应式编程
- 灵活的缓存策略
- 便捷的多域名支持
- 完整的日志监控能力
实际使用中可根据项目需求灵活调整拦截器配置、缓存策略以及错误处理逻辑。建议配合Hilt等依赖注入框架实现更好的组件管理。