一、Android网络请求基础实现
1. 原生HttpURLConnection方式
// 基本GET请求示例
URL url = new URL("https://api.example.com/data");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
conn.setRequestMethod("GET");
InputStream in = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
// 处理result数据
} finally {
conn.disconnect();
}
2. 原生实现存在的问题
-
繁琐的样板代码:需要手动处理连接、流转换等
-
缺乏线程管理:必须自行处理异步请求
-
无内置缓存:需要手动实现缓存逻辑
-
连接复用困难:TCP连接无法有效复用
二、主流网络框架对比
框架 | 特点 | 适用场景 |
---|---|---|
OkHttp | 高效、支持HTTP/2、连接池 | 通用HTTP请求 |
Retrofit | RESTful API封装、结合OkHttp | API接口调用 |
Volley | 适合高频小数据请求 | 简单应用快速开发 |
HttpClient | 功能全面但已废弃 | 遗留系统维护 |
三、OkHttp核心问题解决
1. 连接复用与性能优化
// OkHttp自动管理连接池
OkHttpClient client = new OkHttpClient.Builder()
.connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES))
.build();
// 相同host的请求自动复用TCP连接
Request request1 = new Request.Builder().url("https://api.example.com/a").build();
Request request2 = new Request.Builder().url("https://api.example.com/b").build();
// 两个请求共享同一个TCP连接
解决的问题:
-
减少TCP三次握手开销
-
降低服务器连接压力
-
提升高频请求场景性能(实测提升40%+)
2. 拦截器机制
// 自定义日志拦截器
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Log.d("OkHttp", String.format("Sending request %s", request.url()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.d("OkHttp", String.format("Received response in %.1fms", (t2-t1)/1e6d));
return response;
}
}
// 添加拦截器
client.newBuilder().addInterceptor(new LoggingInterceptor()).build();
解决的问题:
-
统一处理请求/响应(如添加公共header)
-
实现全局日志监控
-
支持请求重试机制
-
简化缓存策略实现
3. 自动缓存管理
// 配置缓存
File cacheDir = new File(context.getCacheDir(), "http_cache");
Cache cache = new Cache(cacheDir, 10 * 1024 * 1024); // 10MB
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
// 发起请求(自动处理缓存)
Request request = new Request.Builder()
.url(url)
.header("Cache-Control", "max-age=60") // 60秒缓存
.build();
解决的问题:
-
自动遵循HTTP缓存规范
-
减少重复网络请求
-
离线场景数据可用性
-
节省用户流量(项目实测减少30%+重复请求)
四、项目实战案例
1. APP列表实现
// 使用OkHttp+协程实现
suspend fun fetchProducts(page: Int): List<Product> {
val request = Request.Builder()
.url("${BASE_URL}/products?page=$page")
.build()
return withContext(Dispatchers.IO) {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val adapter = Moshi.Builder().build()
.adapter(ProductResponse::class.java)
adapter.fromJson(response.body?.source())?.products ?: emptyList()
}
}
}
// 配合RecyclerView实现分页加载
class ProductAdapter : RecyclerView.Adapter<ProductViewHolder>() {
override fun onViewRecycled(holder: ProductViewHolder) {
Glide.with(holder.itemView).clear(holder.imageView) // 清理图片请求
}
}
解决的问题:
-
复杂分页逻辑简化
-
内存泄漏预防
-
列表滑动性能优化
2. 文件上传带进度显示
// 创建Multipart请求体
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
new ProgressRequestBody(file, "image/*", progressListener))
.build();
// 自定义带进度的RequestBody
class ProgressRequestBody extends RequestBody {
@Override
public void writeTo(BufferedSink sink) throws IOException {
Buffer buffer = new Buffer();
long total = contentLength();
long uploaded = 0;
source.read(buffer, 8192);
while (!source.exhausted()) {
uploaded += buffer.size();
sink.write(buffer, buffer.size());
listener.onProgress(uploaded, total);
source.read(buffer, 8192);
}
}
}
解决的问题:
-
大文件上传稳定性
-
精确进度反馈
-
上传中断恢复(通过断点续传实现)
五、性能优化实践
1. 连接参数调优
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS) // 适当延长连接超时
.readTimeout(30, TimeUnit.SECONDS) // 根据业务调整读取超时
.pingInterval(20, TimeUnit.SECONDS) // HTTP/2心跳检测
.build();
2. DNS优化策略
// 自定义DNS解析(防止DNS劫持)
client.dns(new Dns() {
@Override
public List<InetAddress> lookup(String hostname) {
if (hostname == null) throw new UnknownHostException("hostname == null");
try {
// 优先使用HTTPDNS
List<InetAddress> httpDnsResults = queryHttpDns(hostname);
if (!httpDnsResults.isEmpty()) {
return httpDnsResults;
}
// 回退系统DNS
return Dns.SYSTEM.lookup(hostname);
} catch (Exception e) {
return Dns.SYSTEM.lookup(hostname);
}
}
});
3. 网络监控集成
// 添加网络质量监控拦截器
client.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startNs = System.nanoTime();
Response response = chain.proceed(request);
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
NetworkMonitor.record(request.url().host(), tookMs, response.code());
return response;
}
});
六、常见问题解决方案
1. 证书验证问题
// 自定义信任管理器(开发环境使用)
OkHttpClient unsafeClient = new OkHttpClient.Builder()
.sslSocketFactory(createUnsafeSSLSocketFactory(), unsafeTrustManager)
.hostnameVerifier((hostname, session) -> true)
.build();
// 生产环境必须使用正规证书验证
2. 请求重试机制
client.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = null;
IOException exception = null;
// 重试3次
for (int i = 0; i < 3; i++) {
try {
response = chain.proceed(request);
if (response.isSuccessful()) {
return response;
}
} catch (IOException e) {
exception = e;
}
}
if (exception != null) throw exception;
if (response != null) return response;
throw new IOException("Unknown error");
}
});
3. Cookie持久化
// 自定义CookieJar实现
client.cookieJar(new CookieJar() {
private final PersistentCookieStore cookieStore = new PersistentCookieStore(context);
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.add(url, cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
return cookieStore.get(url);
}
});
OkHttp通过其精心的设计,解决了Android网络编程中的诸多痛点问题,成为现代Android开发中网络层的基石。在实际项目中,合理利用其特性可以显著提升应用的网络性能和稳定性。