1. 为什么我们需要响应式网络框架?
在移动应用开发中,网络请求是最基础也是最频繁的操作之一。传统网络请求方式存在几个明显痛点:回调地狱让代码难以维护、线程切换繁琐容易出错、请求生命周期管理复杂。这些问题在复杂业务场景下会被放大,导致代码可读性和可维护性急剧下降。
响应式编程范式恰好能完美解决这些问题。它通过数据流的概念,将网络请求、数据处理和UI更新串联成一条清晰的流水线。OkHttp3作为底层网络库提供高效的HTTP实现,Retrofit2将HTTP API转换为Java接口,RxJava3则负责线程调度和响应式数据处理,三者组合形成了Android平台上最强大的网络请求解决方案。
2. 框架搭建全流程解析
2.1 基础环境配置
首先在build.gradle中添加必要依赖:
groovy复制dependencies {
// OkHttp核心库
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
// OkHttp日志拦截器
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
// Retrofit核心库
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Retrofit的RxJava适配器
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
// Retrofit的Gson转换器
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// RxJava核心库
implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
// RxAndroid
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
}
注意:版本号请根据项目实际情况选择最新稳定版,不同版本间可能存在API差异。
2.2 OkHttp3客户端配置
OkHttp3是整个网络框架的底层引擎,我们可以通过OkHttpClient.Builder进行深度定制:
kotlin复制val okHttpClient = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS) // 连接超时
.readTimeout(15, TimeUnit.SECONDS) // 读取超时
.writeTimeout(15, TimeUnit.SECONDS) // 写入超时
.addInterceptor(HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
})
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer $token")
.build()
chain.proceed(request)
}
.build()
关键配置项说明:
- 超时设置:根据网络环境合理设置,移动网络建议10-15秒
- 日志拦截器:调试阶段开启BODY级别,生产环境关闭
- 通用Header:如认证Token可以在这里统一添加
2.3 Retrofit2服务接口定义
Retrofit的强大之处在于将HTTP API转换为Java接口:
kotlin复制interface ApiService {
@GET("user/{id}")
fun getUser(@Path("id") userId: String): Single<User>
@POST("user/update")
fun updateUser(@Body user: User): Completable
@GET("news/list")
fun getNewsList(
@Query("page") page: Int,
@Query("size") size: Int
): Observable<List<News>>
}
注解说明:
@GET/@POST:指定HTTP方法@Path:替换URL路径参数@Query:添加URL查询参数@Body:将对象作为请求体发送
2.4 构建Retrofit实例
将配置好的OkHttpClient与Retrofit结合:
kotlin复制val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
关键点:
- baseUrl必须以"/"结尾
- GsonConverterFactory负责JSON序列化
- RxJava3CallAdapterFactory实现响应式适配
3. RxJava3响应式处理实战
3.1 基本请求示例
kotlin复制apiService.getUser("123")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ user ->
// 处理成功结果
}, { error ->
// 处理错误
})
线程调度说明:
- subscribeOn:指定请求执行的线程(通常为IO线程)
- observeOn:指定结果回调的线程(通常为主线程)
3.2 复杂数据处理
RxJava的强大之处在于丰富的数据操作符:
kotlin复制apiService.getNewsList(1, 20)
.flatMap { newsList ->
// 先过滤出置顶新闻
Observable.fromIterable(newsList)
.filter { it.isTop }
.toList()
.toObservable()
}
.delay(1, TimeUnit.SECONDS) // 延迟1秒显示
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ topNews ->
// 显示置顶新闻
}, { error ->
// 错误处理
})
常用操作符:
- flatMap:转换数据流
- filter:过滤数据
- delay:延迟发射
- toList:将多个数据打包成列表
3.3 请求组合与并发
多个请求的组合处理:
kotlin复制Single.zip(
apiService.getUserProfile(userId),
apiService.getUserOrders(userId),
BiFunction { profile, orders ->
UserData(profile, orders)
}
).subscribe({ combinedData ->
// 处理合并后的数据
}, { error ->
// 错误处理
})
4. 高级功能实现
4.1 文件上传下载
文件上传实现:
kotlin复制@Multipart
@POST("file/upload")
fun uploadFile(
@Part file: MultipartBody.Part,
@Part("description") description: RequestBody
): Single<UploadResult>
// 使用示例
val filePart = MultipartBody.Part.createFormData(
"file",
file.name,
file.asRequestBody("image/*".toMediaType())
)
apiService.uploadFile(filePart, "文件描述".toRequestBody())
.subscribe({ result ->
// 上传成功
}, { error ->
// 错误处理
})
文件下载实现:
kotlin复制@Streaming
@GET
fun downloadFile(@Url fileUrl: String): Single<ResponseBody>
// 使用示例
apiService.downloadFile("https://example.com/file.zip")
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io()) // 保持在IO线程写入文件
.subscribe({ responseBody ->
val file = File(downloadDir, "file.zip")
responseBody.byteStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
}, { error ->
// 错误处理
})
4.2 请求重试机制
kotlin复制apiService.getUser("123")
.retryWhen { errors ->
errors.zipWith(Observable.range(1, 3), { error, retryCount ->
if (retryCount < 3 && error is SocketTimeoutException) {
Observable.timer(1, TimeUnit.SECONDS)
} else {
Observable.error(error)
}
}).flatMap { it }
}
.subscribe({ user ->
// 处理结果
}, { error ->
// 最终错误处理
})
4.3 请求缓存策略
通过OkHttp拦截器实现缓存:
kotlin复制val cacheSize = 10 * 1024 * 1024 // 10MB
val cache = Cache(File(context.cacheDir, "http_cache"), cacheSize.toLong())
val okHttpClient = OkHttpClient.Builder()
.cache(cache)
.addInterceptor { chain ->
var request = chain.request()
if (!isNetworkAvailable(context)) {
request = request.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=604800")
.build()
}
chain.proceed(request)
}
.addNetworkInterceptor { chain ->
val response = chain.proceed(chain.request())
response.newBuilder()
.header("Cache-Control", "public, max-age=60")
.build()
}
.build()
5. 常见问题与解决方案
5.1 内存泄漏预防
RxJava订阅可能导致内存泄漏,解决方案:
kotlin复制private val disposables = CompositeDisposable()
fun fetchData() {
apiService.getData()
.subscribe({ data ->
// 处理数据
}, { error ->
// 处理错误
})
.also { disposables.add(it) }
}
override fun onDestroy() {
super.onDestroy()
disposables.clear()
}
5.2 错误统一处理
创建全局错误处理器:
kotlin复制abstract class RxErrorHandler : Consumer<Throwable> {
override fun accept(error: Throwable) {
when (error) {
is SocketTimeoutException -> handleTimeout()
is ConnectException -> handleNetworkError()
is HttpException -> handleHttpError(error)
else -> handleUnknownError(error)
}
}
abstract fun handleTimeout()
abstract fun handleNetworkError()
abstract fun handleHttpError(error: HttpException)
abstract fun handleUnknownError(error: Throwable)
}
// 使用示例
apiService.getData()
.subscribe({ data ->
// 处理数据
}, RxErrorHandlerImpl())
5.3 调试技巧
启用OkHttp日志拦截器:
kotlin复制val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
日志格式说明:
- --> 请求开始
- <-- 响应开始
- 请求/响应头
- 请求/响应体(如有)
6. 性能优化实践
6.1 连接池优化
kotlin复制val connectionPool = ConnectionPool(
maxIdleConnections = 5,
keepAliveDuration = 5,
timeUnit = TimeUnit.MINUTES
)
val okHttpClient = OkHttpClient.Builder()
.connectionPool(connectionPool)
.build()
参数建议:
- maxIdleConnections:5-10个(根据应用请求量调整)
- keepAliveDuration:5-10分钟
6.2 DNS优化
使用HTTPDNS替代系统DNS:
kotlin复制class CustomDns : Dns {
override fun lookup(hostname: String): List<InetAddress> {
return try {
// 先尝试HTTPDNS查询
val httpDnsResult = queryHttpDns(hostname)
if (httpDnsResult.isNotEmpty()) {
return httpDnsResult.map { InetAddress.getByName(it) }
}
// 回退到系统DNS
Dns.SYSTEM.lookup(hostname)
} catch (e: Exception) {
Dns.SYSTEM.lookup(hostname)
}
}
}
val okHttpClient = OkHttpClient.Builder()
.dns(CustomDns())
.build()
6.3 请求合并
使用RxJava的zip操作符合并请求:
kotlin复制Single.zip(
apiService.getUserInfo(userId),
apiService.getUserOrders(userId),
apiService.getUserMessages(userId),
Function3 { info, orders, messages ->
CombinedData(info, orders, messages)
}
).subscribe({ combinedData ->
// 更新UI
}, { error ->
// 错误处理
})
7. 测试策略
7.1 Mock Server测试
使用MockWebServer进行单元测试:
kotlin复制val mockWebServer = MockWebServer()
@Before
fun setup() {
mockWebServer.start()
val retrofit = Retrofit.Builder()
.baseUrl(mockWebServer.url("/"))
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build()
apiService = retrofit.create(ApiService::class.java)
}
@Test
fun testGetUser() {
// 准备模拟响应
mockWebServer.enqueue(
MockResponse()
.setBody("""{"id":"123","name":"test"}""")
.setResponseCode(200)
)
// 执行测试
apiService.getUser("123")
.test()
.assertValue { user -> user.id == "123" }
.assertComplete()
}
@After
fun tearDown() {
mockWebServer.shutdown()
}
7.2 流量统计
通过OkHttp拦截器统计网络流量:
kotlin复制class TrafficInterceptor : Interceptor {
private var uploadBytes = 0L
private var downloadBytes = 0L
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
// 计算上传流量
val requestBody = request.body
if (requestBody != null) {
uploadBytes += requestBody.contentLength()
}
val response = chain.proceed(request)
// 计算下载流量
val responseBody = response.body
if (responseBody != null) {
downloadBytes += responseBody.contentLength()
}
return response
}
fun getUploadBytes() = uploadBytes
fun getDownloadBytes() = downloadBytes
}
8. 架构设计建议
8.1 分层设计
推荐的三层架构:
- 数据层:纯Retrofit接口定义
- 领域层:Repository处理业务逻辑
- 表现层:ViewModel/Presenter与UI交互
kotlin复制class UserRepository(private val apiService: ApiService) {
fun getUser(userId: String): Single<User> {
return apiService.getUser(userId)
.map { user ->
// 数据转换或业务处理
user.copy(avatar = processAvatarUrl(user.avatar))
}
}
}
class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
fun loadUser(userId: String) {
userRepository.getUser(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ user ->
_user.value = user
}, { error ->
// 错误处理
})
}
}
8.2 依赖注入
使用Hilt实现依赖注入:
kotlin复制@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.build()
}
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build()
}
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
9. 兼容性处理
9.1 多BaseUrl支持
通过Interceptor动态修改BaseUrl:
kotlin复制class BaseUrlInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val newUrl = when (request.header("X-Base-Url")) {
"auth" -> "https://auth.api.example.com/"
"pay" -> "https://pay.api.example.com/"
else -> null
}
newUrl?.let {
val newFullUrl = request.url.toString()
.replace("https://api.example.com/", it)
request = request.newBuilder()
.url(newFullUrl)
.removeHeader("X-Base-Url")
.build()
}
return chain.proceed(request)
}
}
9.2 接口版本管理
通过Header或URL路径管理版本:
kotlin复制val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("API-Version", "2.0")
.build()
chain.proceed(request)
}
.build()
// 或者通过URL路径
@GET("v2/user/{id}")
fun getUserV2(@Path("id") userId: String): Single<User>
10. 安全加固措施
10.1 HTTPS证书锁定
kotlin复制val certificatePinner = CertificatePinner.Builder()
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build()
val okHttpClient = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
10.2 请求签名
kotlin复制val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val originalRequest = chain.request()
val timestamp = System.currentTimeMillis().toString()
val nonce = UUID.randomUUID().toString()
val signature = generateSignature(
originalRequest.method(),
originalRequest.url().encodedPath(),
timestamp,
nonce,
secretKey
)
val signedRequest = originalRequest.newBuilder()
.addHeader("X-Timestamp", timestamp)
.addHeader("X-Nonce", nonce)
.addHeader("X-Signature", signature)
.build()
chain.proceed(signedRequest)
}
.build()
在实际项目中,这套响应式网络框架已经过多个大型App验证,能够稳定支撑日均百万级的API请求。关键在于根据业务特点合理配置各项参数,并建立完善的错误处理机制。
