🚀 Android 网络优化:体系化实战指南
🧩 1. 网络优化的核心目标
- 降低延迟(Latency)
- 减少流量(Traffic)
- 提升成功率(Success Rate)
- 提升吞吐(Throughput)
- 稳定性(Stability)
这些目标最终都要能映射到可量化指标:TTFB、RTT、成功率、重试率、平均包大小、QPS 等。
⚡ 2. 端侧网络优化(Android App 内)
2.1 HTTP 层优化(OkHttp / Retrofit)
✔ 连接复用
- 启用 HTTP/2(多路复用)
- 配置 ConnectionPool(默认 5 个连接、5 分钟 keep-alive)
- 避免频繁创建 OkHttpClient(全局单例)
✔ DNS 优化
- 使用 异步 DNS(如 OkHttp DnsOverHttps)
- 自建 DNS 缓存(TTL 控制)
- 支持 多 DNS 源兜底(系统 DNS → DoH → HTTPDNS)
✔ 压缩与数据裁剪
- 开启 gzip/deflate
- 服务端返回字段裁剪(减少 JSON 体积)
- 使用 protobuf / flatbuffers(适合高频接口)
✔ 请求合并与批处理
- 多个小请求 → 合并为一个批处理请求
- 典型场景:埋点、配置拉取、列表批量查询
✔ 超时与重试策略
- connectTimeout:3s
- readTimeout:5–10s
- writeTimeout:5–10s
- 重试策略:指数退避 + 最大重试次数
2.2 网络调度优化
✔ 前台/后台调度
- 后台任务使用 WorkManager + 网络约束
- 前台任务优先级高,避免被后台任务阻塞
✔ 并发控制
- 限制同时发起的请求数量(如 6–10)
- 避免瞬时洪峰导致队列阻塞
2.3 缓存体系优化
✔ 本地缓存(App 内)
- LRU 内存缓存
- DiskLruCache
- Room/SQLite 缓存
✔ HTTP 缓存
- Cache-Control
- ETag / If-Modified-Since
- OkHttp Cache
✔ 预加载
- 首页数据预加载
- 配置预拉取
- 图片预加载(Glide preload)
2.4 弱网优化
✔ 弱网检测
- 网络质量分级:Excellent / Good / Poor / Bad
- 基于 RTT、丢包率、带宽估计(如 Cronet)
✔ 降级策略
- 降低图片质量
- 降低视频码率
- 减少接口调用
- 使用缓存兜底
🌐 3. 服务端配合优化
3.1 接口设计优化
- 减少嵌套层级
- 字段裁剪
- 批量接口
- 分页接口
3.2 CDN 加速
- 静态资源(图片、视频、配置)
- 边缘缓存
3.3 负载均衡
- 多机房
- 就近接入
- 灾备切换
🧪 4. 网络质量监控体系(可直接用于团队文档)
4.1 关键指标
| 指标 | 说明 |
|---|---|
| TTFB | 首字节时间 |
| RTT | 往返延迟 |
| 成功率 | 请求成功比例 |
| 超时率 | 超时占比 |
| 平均包大小 | 请求/响应体积 |
| QPS | 每秒请求数 |
4.2 监控方案
- OkHttp EventListener
- 自定义 Interceptor
- 全链路 Trace ID
- 弱网模拟器(Android Studio)
🧱 5. 架构级优化(你会喜欢的部分)
✔ 使用 Cronet 替代 OkHttp(可选)
- Google 自研网络栈
- 更好的弱网表现
- 更快的 DNS、TLS、HTTP/2
✔ 使用 QUIC / HTTP/3
- 更低延迟
- 更抗丢包
- 移动网络体验显著提升
✔ 自研网络 SDK(大厂常见)
- 统一调度
- 统一缓存
- 统一监控
- 统一降级策略
🛠 6. 可复用的 Android 网络优化模板(你可以直接给团队用)
6.1 OkHttpClient 全局模板
kotlin
object HttpClientProvider {
val client: OkHttpClient by lazy {
OkHttpClient.Builder()
.connectionPool(ConnectionPool(8, 5, TimeUnit.MINUTES))
.dns(OptimizedDns()) // HTTPDNS + 系统 DNS
.retryOnConnectionFailure(true)
.connectTimeout(3, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.addInterceptor(CompressionInterceptor())
.addInterceptor(MonitorInterceptor())
.cache(Cache(cacheDir, 50L * 1024 * 1024))
.build()
}
}