Android Volley Response响应处理机制
一、Android Volley Response响应处理机制概述
1.1 Volley框架中的响应处理核心地位
在Android Volley框架中,响应处理机制是连接网络请求与应用逻辑的关键环节。当应用发起一个网络请求后,服务器返回的数据需要经过一系列处理才能被应用使用,这个过程就是响应处理。Volley的响应处理机制不仅负责接收原始网络数据,还包括数据解析、线程切换、缓存处理以及错误反馈等功能,是整个框架中不可或缺的一部分。
1.2 Response响应处理的基本流程
Volley的响应处理流程可以概括为以下几个主要步骤:
- 网络请求执行:Request对象被添加到RequestQueue中,由NetworkDispatcher线程执行网络请求。
- 原始响应获取:通过HttpStack获取服务器返回的原始数据,封装在NetworkResponse对象中。
- 响应解析:将NetworkResponse解析为应用需要的格式(如String、JSON、Bitmap等)。
- 线程切换:将解析后的响应从网络线程切换到主线程,以便更新UI。
- 响应分发:将解析后的响应数据传递给应用层的回调函数。
- 缓存处理:如果请求需要缓存,将响应数据存入缓存。
1.3 Response相关类的基本架构
Volley中与响应处理相关的核心类包括:
- NetworkResponse:封装从网络获取的原始响应数据,包括状态码、响应头、响应体等信息。
- Response:泛型类,表示解析后的响应结果,包含响应数据和缓存信息。
- Response.Listener:接口,定义请求成功时的回调方法。
- Response.ErrorListener:接口,定义请求失败时的回调方法。
- ResponseParser:接口,定义响应解析的方法。
- HttpHeaderParser:工具类,用于解析HTTP响应头,处理缓存相关信息。
下面是这些类的基本结构和关键代码:
package com.android.volley;
import java.util.Map;
/**
* 表示从网络获取的原始响应
*/
public class NetworkResponse {
// HTTP状态码
public final int statusCode;
// 响应数据
public final byte[] data;
// 响应头
public final Map<String, String> headers;
// 响应是否未修改(用于缓存)
public final boolean notModified;
// 网络请求耗时(毫秒)
public final long networkTimeMs;
/**
* 构造一个新的网络响应
* @param statusCode HTTP状态码
* @param data 响应数据
* @param headers 响应头
* @param notModified 响应是否未修改
*/
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
boolean notModified) {
this(statusCode, data, headers, notModified, 0);
}
/**
* 构造一个新的网络响应,包含网络请求耗时
* @param statusCode HTTP状态码
* @param data 响应数据
* @param headers 响应头
* @param notModified 响应是否未修改
* @param networkTimeMs 网络请求耗时
*/
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
boolean notModified, long networkTimeMs) {
this.statusCode = statusCode;
this.data = data;
this.headers = headers;
this.notModified = notModified;
this.networkTimeMs = networkTimeMs;
}
}
/**
* 表示解析后的响应
*/
public class Response<T> {
// 响应数据
public final T result;
// 错误信息
public final VolleyError error;
// 缓存条目
public final Cache.Entry cacheEntry;
// 响应是否为中间结果(例如需要刷新的缓存响应)
public boolean intermediate = false;
/**
* 私有构造函数,使用静态工厂方法创建实例
*/
private Response(T result, Cache.Entry cacheEntry) {
this.result = result;
this.error = null;
this.cacheEntry = cacheEntry;
}
/**
* 私有构造函数,使用静态工厂方法创建实例
*/
private Response(VolleyError error) {
this.result = null;
this.error = error;
this.cacheEntry = null;
}
/**
* 判断响应是否成功
* @return 如果成功返回true,否则返回false
*/
public boolean isSuccess() {
return error == null;
}
/**
* 静态工厂方法,创建成功的响应
* @param result 响应数据
* @param cacheEntry 缓存条目
* @return 成功的响应对象
*/
public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
return new Response<T>(result, cacheEntry);
}
/**
* 静态工厂方法,创建失败的响应
* @param error 错误信息
* @return 失败的响应对象
*/
public static <T> Response<T> error(VolleyError error) {
return new Response<T>(error);
}
/**
* 请求成功的回调接口
*/
public interface Listener<T> {
/**
* 当请求成功时调用
* @param response 响应数据
*/
public void onResponse(T response);
}
/**
* 请求失败的回调接口
*/
public interface ErrorListener {
/**
* 当请求失败时调用
* @param error 错误信息
*/
public void onErrorResponse(VolleyError error);
}
}
/**
* 响应解析器接口
*/
public interface ResponseParser {
/**
* 解析网络响应
* @param response 网络响应
* @return 解析后的响应
*/
Response<?> parseNetworkResponse(NetworkResponse response);
}
/**
* HTTP响应头解析工具类
*/
public class HttpHeaderParser {
/**
* 从响应头中解析缓存条目
* @param response 网络响应
* @return 缓存条目
*/
public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
long now = System.currentTimeMillis();
Map<String, String> headers = response.headers;
long serverDate = 0;
long serverExpires = 0;
long softExpire = 0;
long finalExpire = 0;
long maxAge = 0;
long staleWhileRevalidate = 0;
boolean hasCacheControl = false;
boolean mustRevalidate = false;
// 获取Date头
String serverEtag = null;
String headerValue;
headerValue = headers.get("Date");
if (headerValue != null) {
serverDate = parseDateAsEpoch(headerValue);
}
// 获取Cache-Control头
headerValue = headers.get("Cache-Control");
if (headerValue != null) {
hasCacheControl = true;
String[] tokens = headerValue.split(",");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i].trim();
if (token.equals("no-cache") || token.equals("no-store")) {
return null;
} else if (token.startsWith("max-age=")) {
try {
maxAge = Long.parseLong(token.substring(8));
} catch (Exception e) {
// 忽略解析错误
}
} else if (token.startsWith("stale-while-revalidate=")) {
try {
staleWhileRevalidate = Long.parseLong(token.substring(23));
} catch (Exception e) {
// 忽略解析错误
}
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
mustRevalidate = true;
}
}
}
// 获取Expires头
headerValue = headers.get("Expires");
if (headerValue != null) {
serverExpires = parseDateAsEpoch(headerValue);
}
// 获取ETag头
serverEtag = headers.get("ETag");
// 计算缓存时间
if (hasCacheControl) {
// 如果有Cache-Control头,使用它来计算缓存时间
softExpire = now + maxAge * 1000;
finalExpire = mustRevalidate
? softExpire
: softExpire + staleWhileRevalidate * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
// 如果没有Cache-Control头但有Expires头,使用它来计算缓存时间
softExpire = now + (serverExpires - serverDate);
finalExpire = softExpire;
}
Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = finalExpire;
entry.serverDate = serverDate;
entry.responseHeaders = headers;
return entry;
}
/**
* 将HTTP日期字符串解析为毫秒数
* @param dateStr 日期字符串
* @return 毫秒数
*/
public static long parseDateAsEpoch(String dateStr) {
try {
// RFC1123格式日期解析
return DateUtils.parseDate(dateStr).getTime();
} catch (ParseException e) {
// 如果解析失败,返回0
return 0;
}
}
// 其他解析方法...
}
二、Response响应处理的核心流程
2.1 从网络请求到响应接收
当Request对象被添加到RequestQueue后,会经历网络请求执行阶段,最终获取到服务器响应:
// NetworkDispatcher类的run方法,负责执行网络请求
@Override
public void run() {
// 设置线程优先级为后台线程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request<?> request;
try {
// 从网络队列中获取请求,如果队列为空则阻塞
request = mNetworkQueue.take();
} catch (InterruptedException e) {
// 如果线程被中断,检查是否需要退出
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// 检查请求是否已取消
if (request.isCanceled()) {
request.finish("network-discard-canceled");
continue;
}
// 为请求添加流量统计标签
addTrafficStatsTag(request);
// 执行网络请求,获取原始响应
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// 检查服务器返回的重定向
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// 解析网络响应
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// 如果请求应该被缓存,将响应写入缓存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// 标记请求已分发响应
request.markDelivered();
// 分发响应到主线程
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
// 解析网络错误
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
// 处理其他异常
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
}
}
2.2 原始响应的封装与传递
当网络请求完成后,服务器返回的数据会被封装到NetworkResponse对象中:
// BasicNetwork类的performRequest方法,执行实际的网络请求
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
// 循环处理重定向
while (true) {
HttpStack stack = mHttpStack;
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
// 准备请求头
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
// 执行HTTP请求
httpResponse = stack.performRequest(request, headers);
// 获取HTTP状态码
final int statusCode = httpResponse.getStatusCode();
// 获取响应头
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// 如果状态码是304(Not Modified)
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
// 处理304状态码
Cache.Entry entry = request.getCacheEntry();
if (entry == null) {
// 如果没有缓存条目,返回一个空响应
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null,
responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
// 返回缓存的响应
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED,
entry.data, responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
// 读取响应数据
if (httpResponse.getEntity() != null) {
responseContents = entityToBytes(httpResponse.getEntity());
} else {
// 对于没有响应体的请求,创建一个空的响应体
responseContents = new byte[0];
}
// 计算网络请求耗时
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
// 记录请求统计信息
logSlowRequests(requestLifetime, request, responseContents, statusCode);
// 如果状态码不是200,抛出异常
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
// 返回网络响应
return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
SystemClock.elapsedRealtime() - requestStart);
} catch (SocketTimeoutException e) {
// 处理超时异常
attemptRetryOnException("socket", request, new TimeoutError());
} catch (MalformedURLException e) {
// 处理URL格式错误
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
// 处理IO异常
int statusCode = 0;
NetworkResponse networkResponse = null;
// 尝试获取HTTP状态码
if (httpResponse != null) {
statusCode = httpResponse.getStatusCode();
} else {
throw new NoConnectionError(e);
}
// 记录错误日志
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
// 处理服务器错误
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
// 处理特定的HTTP状态码
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED ||
statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode == HttpURLConnection.HTTP_MOVED_PERM ||
statusCode == HttpURLConnection.HTTP_MOVED_TEMP ||
statusCode == HttpURLConnection.HTTP_SEE_OTHER ||
statusCode == 307) {
// 处理重定向
String newUrl = responseHeaders.get("Location");
if (newUrl == null) {
// 如果没有Location头,抛出异常
throw new VolleyError(networkResponse);
}
// 更新请求URL并继续循环
request.setRedirectUrl(newUrl);
continue;
} else {
// 其他错误状态码
throw new ServerError(networkResponse);
}
} else {
// 没有响应内容的错误
attemptRetryOnException("network", request, new NetworkError(e));
}
}
}
}
2.3 响应解析过程
获取到NetworkResponse后,需要将其解析为应用可以使用的格式:
// Request类的parseNetworkResponse方法,由子类实现具体解析逻辑
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
// StringRequest类的parseNetworkResponse方法,将响应解析为字符串
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
// 根据响应头中的字符集解码响应数据
String charset = getCharsetFromHeaders(response.headers);
parsed = new String(response.data, charset);
} catch (UnsupportedEncodingException e) {
// 如果字符集不支持,使用默认字符集
parsed = new String(response.data);
}
// 返回解析成功的响应,包含解析后的字符串和缓存信息
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
// JsonObjectRequest类的parseNetworkResponse方法,将响应解析为JSONObject
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
// 从响应数据中解析JSON字符串
String jsonString = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
// 将JSON字符串解析为JSONObject
return Response.success(
new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
// 返回解析错误
return Response.error(new ParseError(e));
} catch (JSONException je) {
// 返回解析错误
return Response.error(new ParseError(je));
}
}
// ImageRequest类的parseNetworkResponse方法,将响应解析为Bitmap
@Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
// 同步锁,防止同时进行多个图片解码操作
synchronized (sDecodeLock) {
try {
// 解码图片
return doParse(response);
} catch (OutOfMemoryError e) {
// 内存不足错误处理
VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl());
return Response.error(new ParseError(e));
}
}
}
// ImageRequest类的doParse方法,实际执行图片解码
private Response<Bitmap> doParse(NetworkResponse response) {
byte[] data = response.data;
// 先获取图片的尺寸信息
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
// 获取原始图片尺寸
int actualWidth = options.outWidth;
int actualHeight = options.outHeight;
// 计算目标尺寸
int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,
actualWidth, actualHeight, getDefaultScaleType(mMaxWidth, mMaxHeight));
int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,
actualHeight, actualWidth, getDefaultScaleType(mMaxWidth, mMaxHeight));
// 计算采样率
options.inJustDecodeBounds = false;
options.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
// 如果需要,调整图片尺寸
if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth ||
tempBitmap.getHeight() > desiredHeight)) {
Bitmap bitmap = Bitmap.createScaledBitmap(tempBitmap,
desiredWidth, desiredHeight, true);
tempBitmap.recycle();
return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
} else {
return Response.success(tempBitmap, HttpHeaderParser.parseCacheHeaders(response));
}
}
2.4 线程切换与响应分发
解析后的响应需要从网络线程切换到主线程,以便安全地更新UI:
// ExecutorDelivery类,负责将响应分发到主线程
public class ExecutorDelivery implements ResponseDelivery {
// 主线程Handler
private final Handler mResponseHandler;
/**
* 构造函数,使用主线程Looper创建Handler
*/
public ExecutorDelivery() {
mResponseHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
ResponseDeliveryRunnable runnable = (ResponseDeliveryRunnable) msg.obj;
runnable.run();
}
};
}
/**
* 将响应发布到主线程
*/
@Override
public void postResponse(Request<?> request, Response<?> response) {
postResponse(request, response, null);
}
/**
* 将响应发布到主线程,并在完成后执行回调
*/
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
// 标记请求已开始分发响应
request.markDelivered();
request.addMarker("post-response");
// 创建响应分发任务
ResponseDeliveryRunnable deliveryRunnable =
new ResponseDeliveryRunnable(request, response, runnable);
// 如果请求已取消,不再分发响应
if (request.isCanceled()) {
mResponseHandler.removeCallbacks(deliveryRunnable);
return;
}
// 将任务发送到主线程
mResponseHandler.post(deliveryRunnable);
}
/**
* 将错误响应发布到主线程
*/
@Override
public void postError(Request<?> request, VolleyError error) {
request.addMarker("post-error");
// 解析错误
Response<?> response = Response.error(error);
// 发布错误响应
mResponseHandler.post(new ResponseDeliveryRunnable(request, response, null));
}
/**
* 响应分发任务
*/
@SuppressWarnings("rawtypes")
private static class ResponseDeliveryRunnable implements Runnable {
private final Request mRequest;
private final Response mResponse;
private final Runnable mRunnable;
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
mRequest = request;
mResponse = response;
mRunnable = runnable;
}
@SuppressWarnings("unchecked")
@Override
public void run() {
// 如果请求已取消,不执行回调
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// 处理响应
if (mResponse.isSuccess()) {
// 成功响应,调用请求的成功回调
mRequest.deliverResponse(mResponse.result);
} else {
// 错误响应,调用请求的错误回调
mRequest.deliverError(mResponse.error);
}
// 如果响应是中间结果,不标记请求完成
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
// 标记请求完成
mRequest.finish("done");
}
// 如果有后续任务,执行它
if (mRunnable != null) {
mRunnable.run();
}
}
}
}
2.5 应用层回调的触发
最终,解析后的响应会触发应用层设置的回调函数:
// Request类的deliverResponse方法,将响应分发到应用层
protected void deliverResponse(T response) {
// 调用响应监听器的回调方法
if (mListener != null) {
mListener.onResponse(response);
}
}
// Request类的deliverError方法,将错误分发到应用层
public void deliverError(VolleyError error) {
// 标记响应已分发
mResponseDelivered = true;
// 如果有错误监听器,调用其回调方法
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
// 应用层使用示例
StringRequest request = new StringRequest(
Request.Method.GET,
"https://api.example.com/data",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// 处理成功响应
Log.d(TAG, "Response: " + response);
// 更新UI
textView.setText(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 处理错误响应
Log.e(TAG, "Error: " + error.getMessage());
// 显示错误信息
Toast.makeText(context, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
}
}
);
三、缓存响应的处理机制
3.1 缓存响应的获取与判断
当请求应该被缓存时,Volley会首先检查缓存中是否有可用的响应:
// CacheDispatcher类的run方法,处理缓存请求
@Override
public void run() {
// 设置线程优先级为后台线程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 初始化缓存
mCache.initialize();
while (true) {
try {
// 从缓存队列中获取请求,如果队列为空则阻塞
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
// 检查请求是否已取消
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// 尝试从缓存中获取数据
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// 缓存未命中,将请求添加到网络队列
mNetworkQueue.put(request);
continue;
}
// 检查缓存是否已过期
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
// 缓存已过期,将请求添加到网络队列
mNetworkQueue.put(request);
continue;
}
// 缓存命中且未过期
request.addMarker("cache-hit");
// 解析缓存数据
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
// 检查缓存是否需要刷新
if (entry.refreshNeeded()) {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// 标记响应为软刷新
response.intermediate = true;
// 将请求发送到网络进行刷新,同时分发缓存响应
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// 恢复中断状态
Thread.currentThread().interrupt();
}
}
});
} else {
// 缓存不需要刷新,直接分发响应
mDelivery.postResponse(request, response);
}
} catch (InterruptedException e) {
// 如果线程被中断,退出循环
if (mQuit) {
return;
}
continue;
}
}
}
3.2 缓存条目的解析与验证
当从缓存中获取到响应数据后,需要解析缓存条目并验证其有效性:
// Cache.Entry类,表示缓存中的一个条目
public static class Entry {
// 缓存数据
public byte[] data;
// ETag,用于验证缓存
public String etag;
// 软过期时间(毫秒)
public long softTtl;
// 硬过期时间(毫秒)
public long ttl;
// 服务器时间(毫秒)
public long serverDate;
// 响应头
public Map<String, String> responseHeaders = Collections.emptyMap();
/**
* 判断缓存是否已过期
* @return 如果已过期返回true,否则返回false
*/
public boolean isExpired() {
return this.ttl < System.currentTimeMillis();
}
/**
* 判断缓存是否需要刷新
* @return 如果需要刷新返回true,否则返回false
*/
public boolean refreshNeeded() {
return this.softTtl < System.currentTimeMillis();
}
}
// HttpHeaderParser类的parseCacheHeaders方法,解析响应头生成缓存条目
public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
long now = System.currentTimeMillis();
Map<String, String> headers = response.headers;
long serverDate = 0;
long serverExpires = 0;
long softExpire = 0;
long finalExpire = 0;
long maxAge = 0;
long staleWhileRevalidate = 0;
boolean hasCacheControl = false;
boolean mustRevalidate = false;
// 获取Date头
String serverEtag = null;
String headerValue;
headerValue = headers.get("Date");
if (headerValue != null) {
serverDate = parseDateAsEpoch(headerValue);
}
// 获取Cache-Control头
headerValue = headers.get("Cache-Control");
if (headerValue != null) {
hasCacheControl = true;
String[] tokens = headerValue.split(",");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i].trim();
if (token.equals("no-cache") || token.equals("no-store")) {
return null;
} else if (token.startsWith("max-age=")) {
try {
maxAge = Long.parseLong(token.substring(8));
} catch (Exception e) {
// 忽略解析错误
}
} else if (token.startsWith("stale-while-revalidate=")) {
try {
staleWhileRevalidate = Long.parseLong(token.substring(23));
} catch (Exception e) {
// 忽略解析错误
}
} else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
mustRevalidate = true;
}
}
}
// 获取Expires头
headerValue = headers.get("Expires");
if (headerValue != null) {
serverExpires = parseDateAsEpoch(headerValue);
}
// 获取ETag头
serverEtag = headers.get("ETag");
// 计算缓存时间
if (hasCacheControl) {
// 如果有Cache-Control头,使用它来计算缓存时间
softExpire = now + maxAge * 1000;
finalExpire = mustRevalidate
? softExpire
: softExpire + staleWhileRevalidate * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
// 如果没有Cache-Control头但有Expires头,使用它来计算缓存时间
softExpire = now + (serverExpires - serverDate);
finalExpire = softExpire;
}
// 创建并初始化缓存条目
Cache.Entry entry = new Cache.Entry();
entry.data = response.data;
entry.etag = serverEtag;
entry.softTtl = softExpire;
entry.ttl = finalExpire;
entry.serverDate = serverDate;
entry.responseHeaders = headers;
return entry;
}
3.3 缓存刷新机制
当缓存需要刷新时,Volley会同时分发缓存响应和发起网络请求:
// CacheDispatcher类中处理需要刷新的缓存
if (entry.refreshNeeded()) {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// 标记响应为中间结果
response.intermediate = true;
// 将请求发送到网络进行刷新,同时分发缓存响应
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
// 将请求添加到网络队列进行刷新
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// 恢复中断状态
Thread.currentThread().interrupt();
}
}
});
}
3.4 缓存响应的分发
缓存响应的分发过程与网络响应类似,但有一些特殊处理:
// ExecutorDelivery类的postResponse方法,处理响应分发
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
// 标记请求已开始分发响应
request.markDelivered();
request.addMarker("post-response");
// 创建响应分发任务
ResponseDeliveryRunnable deliveryRunnable =
new ResponseDeliveryRunnable(request, response, runnable);
// 如果请求已取消,不再分发响应
if (request.isCanceled()) {
mResponseHandler.removeCallbacks(deliveryRunnable);
return;
}
// 将任务发送到主线程
mResponseHandler.post(deliveryRunnable);
}
// ResponseDeliveryRunnable类的run方法,实际执行响应分发
@SuppressWarnings("unchecked")
@Override
public void run() {
// 如果请求已取消,不执行回调
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// 处理响应
if (mResponse.isSuccess()) {
// 成功响应,调用请求的成功回调
mRequest.deliverResponse(mResponse.result);
} else {
// 错误响应,调用请求的错误回调
mRequest.deliverError(mResponse.error);
}
// 如果响应是中间结果,不标记请求完成
if (mResponse.intermediate
四、响应处理中的错误机制
4.1 错误类型与分类
Volley框架中定义了多种错误类型,每种错误类型对应不同的网络异常情况:
package com.android.volley;
/**
* Volley错误的基类
*/
public class VolleyError extends Exception {
// 网络响应
public final NetworkResponse networkResponse;
// 网络请求耗时
private long networkTimeMs;
/**
* 构造函数
*/
public VolleyError() {
networkResponse = null;
}
/**
* 构造函数
*/
public VolleyError(NetworkResponse response) {
networkResponse = response;
}
/**
* 构造函数
*/
public VolleyError(String exceptionMessage) {
super(exceptionMessage);
networkResponse = null;
}
/**
* 构造函数
*/
public VolleyError(String exceptionMessage, Throwable reason) {
super(exceptionMessage, reason);
networkResponse = null;
}
/**
* 构造函数
*/
public VolleyError(Throwable cause) {
super(cause);
networkResponse = null;
}
/**
* 设置网络请求耗时
*/
public void setNetworkTimeMs(long networkTimeMs) {
this.networkTimeMs = networkTimeMs;
}
/**
* 获取网络请求耗时
*/
public long getNetworkTimeMs() {
return networkTimeMs;
}
}
/**
* 网络连接错误
*/
public class NetworkError extends VolleyError {
public NetworkError() {
super();
}
public NetworkError(Throwable cause) {
super(cause);
}
public NetworkError(NetworkResponse networkResponse) {
super(networkResponse);
}
}
/**
* 超时错误
*/
public class TimeoutError extends VolleyError {
}
/**
* 服务器错误
*/
public class ServerError extends VolleyError {
public ServerError(NetworkResponse networkResponse) {
super(networkResponse);
}
}
/**
* 认证失败错误
*/
public class AuthFailureError extends VolleyError {
public AuthFailureError() {
super();
}
public AuthFailureError(NetworkResponse response) {
super(response);
}
public AuthFailureError(String message) {
super(message);
}
public AuthFailureError(Throwable cause) {
super(cause);
}
/**
* 获取认证请求头
*/
public Map<String, String> getRequestHeaders() throws AuthFailureError {
return null;
}
/**
* 获取认证凭据
*/
public byte[] getBody() throws AuthFailureError {
return null;
}
}
/**
* 解析错误
*/
public class ParseError extends VolleyError {
public ParseError() {
super();
}
public ParseError(NetworkResponse networkResponse) {
super(networkResponse);
}
public ParseError(Throwable cause) {
super(cause);
}
}
/**
* 取消错误
*/
public class CancelError extends VolleyError {
public CancelError() {
super();
}
public CancelError(String message) {
super(message);
}
public CancelError(Throwable cause) {
super(cause);
}
}
4.2 错误处理流程
当网络请求过程中出现异常时,Volley会捕获异常并进行相应的处理:
// NetworkDispatcher类中处理网络请求异常
try {
// 执行网络请求,获取原始响应
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// 检查服务器返回的重定向
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// 解析网络响应
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// 如果请求应该被缓存,将响应写入缓存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// 标记请求已分发响应
request.markDelivered();
// 分发响应到主线程
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
// 解析网络错误
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
// 处理其他异常
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
// NetworkDispatcher类的parseAndDeliverNetworkError方法
private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
error = request.parseNetworkError(error);
mDelivery.postError(request, error);
}
// Request类的parseNetworkError方法,可由子类重写以处理特定错误
public VolleyError parseNetworkError(VolleyError volleyError) {
return volleyError;
}
// JsonObjectRequest类重写的parseNetworkError方法
@Override
public VolleyError parseNetworkError(VolleyError volleyError) {
if (volleyError.networkResponse != null) {
if (volleyError instanceof ServerError) {
try {
// 尝试解析服务器返回的错误信息
String json = new String(
volleyError.networkResponse.data,
HttpHeaderParser.parseCharset(volleyError.networkResponse.headers));
return new ServerError(new NetworkResponse(
volleyError.networkResponse.statusCode,
json.getBytes(),
volleyError.networkResponse.headers,
volleyError.networkResponse.notModified));
} catch (UnsupportedEncodingException e) {
// 忽略解析错误
}
}
}
return super.parseNetworkError(volleyError);
}
4.3 重试机制
Volley提供了请求重试机制,当出现特定错误时可以尝试重新发送请求:
// RetryPolicy接口定义了重试策略
public interface RetryPolicy {
/**
* 获取当前超时时间(毫秒)
*/
public int getCurrentTimeout();
/**
* 获取当前重试次数
*/
public int getCurrentRetryCount();
/**
* 处理重试
* @param error 导致重试的错误
* @throws VolleyError 如果不应重试,抛出此异常
*/
public void retry(VolleyError error) throws VolleyError;
}
// DefaultRetryPolicy类是默认的重试策略实现
public class DefaultRetryPolicy implements RetryPolicy {
// 默认初始超时时间(毫秒)
public static final int DEFAULT_TIMEOUT_MS = 2500;
// 默认最大重试次数
public static final int DEFAULT_MAX_RETRIES = 1;
// 默认退避乘数
public static final float DEFAULT_BACKOFF_MULT = 1f;
// 当前超时时间
private int mCurrentTimeoutMs;
// 当前重试次数
private int mCurrentRetryCount;
// 最大重试次数
private final int mMaxNumRetries;
// 退避乘数
private final float mBackoffMultiplier;
/**
* 构造函数,使用默认参数
*/
public DefaultRetryPolicy() {
this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
}
/**
* 构造函数
* @param initialTimeoutMs 初始超时时间
* @param maxNumRetries 最大重试次数
* @param backoffMultiplier 退避乘数
*/
public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
mCurrentTimeoutMs = initialTimeoutMs;
mMaxNumRetries = maxNumRetries;
mBackoffMultiplier = backoffMultiplier;
}
/**
* 获取当前超时时间
*/
@Override
public int getCurrentTimeout() {
return mCurrentTimeoutMs;
}
/**
* 获取当前重试次数
*/
@Override
public int getCurrentRetryCount() {
return mCurrentRetryCount;
}
/**
* 获取退避乘数
*/
public float getBackoffMultiplier() {
return mBackoffMultiplier;
}
/**
* 处理重试逻辑
*/
@Override
public void retry(VolleyError error) throws VolleyError {
mCurrentRetryCount++;
mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
// 根据错误类型决定是否重试
if (!isRetryable(error)) {
throw error;
}
// 如果超过最大重试次数,抛出错误
if (mCurrentRetryCount > mMaxNumRetries) {
throw error;
}
}
/**
* 判断错误是否可重试
*/
private boolean isRetryable(VolleyError error) {
if (error instanceof NetworkError || error instanceof TimeoutError) {
return true;
}
return false;
}
}
// BasicNetwork类中应用重试策略
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
// 执行网络请求代码...
try {
// 准备请求头
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
// 执行HTTP请求
httpResponse = stack.performRequest(request, headers);
// 处理响应代码...
} catch (SocketTimeoutException e) {
// 处理超时异常,尝试重试
attemptRetryOnException("socket", request, new TimeoutError());
} catch (IOException e) {
// 处理IO异常
int statusCode = 0;
NetworkResponse networkResponse = null;
// 尝试获取HTTP状态码
if (httpResponse != null) {
statusCode = httpResponse.getStatusCode();
} else {
throw new NoConnectionError(e);
}
// 处理特定的HTTP状态码
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED ||
statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode == HttpURLConnection.HTTP_MOVED_PERM ||
statusCode == HttpURLConnection.HTTP_MOVED_TEMP ||
statusCode == HttpURLConnection.HTTP_SEE_OTHER ||
statusCode == 307) {
// 处理重定向
// ...
} else {
// 其他错误状态码
throw new ServerError(networkResponse);
}
}
}
}
// BasicNetwork类的attemptRetryOnException方法
private void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception)
throws VolleyError {
RetryPolicy retryPolicy = request.getRetryPolicy();
int oldTimeout = request.getTimeoutMs();
try {
// 执行重试策略
retryPolicy.retry(exception);
} catch (VolleyError e) {
// 不再重试,设置请求标记并抛出错误
request.addMarker(
String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
throw e;
}
// 添加重试标记
request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
}
4.4 错误回调的触发
当请求出现错误时,错误信息会通过回调传递给应用层:
// ExecutorDelivery类的postError方法
@Override
public void postError(Request<?> request, VolleyError error) {
request.addMarker("post-error");
// 创建错误响应
Response<?> response = Response.error(error);
// 发布错误响应
mResponseHandler.post(new ResponseDeliveryRunnable(request, response, null));
}
// ResponseDeliveryRunnable类的run方法
@SuppressWarnings("unchecked")
@Override
public void run() {
// 如果请求已取消,不执行回调
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// 处理响应
if (mResponse.isSuccess()) {
// 成功响应处理...
} else {
// 错误响应,调用请求的错误回调
mRequest.deliverError(mResponse.error);
}
// 处理中间响应和完成标记...
}
// Request类的deliverError方法
public void deliverError(VolleyError error) {
// 标记响应已分发
mResponseDelivered = true;
// 如果有错误监听器,调用其回调方法
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
五、响应处理的高级特性
5.1 中间响应机制
Volley支持中间响应机制,允许在获取最终响应之前提供临时数据:
// Response类的intermediate字段
public boolean intermediate = false;
// CacheDispatcher类中处理需要刷新的缓存响应
if (entry.refreshNeeded()) {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// 标记响应为中间结果
response.intermediate = true;
// 将请求发送到网络进行刷新,同时分发缓存响应
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// 恢复中断状态
Thread.currentThread().interrupt();
}
}
});
}
// ResponseDeliveryRunnable类的run方法处理中间响应
@SuppressWarnings("unchecked")
@Override
public void run() {
// 如果请求已取消,不执行回调
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// 处理响应
if (mResponse.isSuccess()) {
// 成功响应,调用请求的成功回调
mRequest.deliverResponse(mResponse.result);
} else {
// 错误响应,调用请求的错误回调
mRequest.deliverError(mResponse.error);
}
// 如果响应是中间结果,不标记请求完成
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
// 标记请求完成
mRequest.finish("done");
}
// 如果有后续任务,执行它
if (mRunnable != null) {
mRunnable.run();
}
}
5.2 响应转换
Volley允许对响应进行转换,以适应不同的应用需求:
// 自定义Request类,支持响应转换
public class CustomRequest<T> extends Request<T> {
private final Response.Listener<T> mListener;
private final Converter<NetworkResponse, T> mConverter;
/**
* 构造函数
*/
public CustomRequest(int method, String url, Response.Listener<T> listener,
Response.ErrorListener errorListener, Converter<NetworkResponse, T> converter) {
super(method, url, errorListener);
mListener = listener;
mConverter = converter;
}
/**
* 解析网络响应
*/
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
// 使用转换器转换响应
T result = mConverter.convert(response);
return Response.success(result, HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
/**
* 分发响应
*/
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
/**
* 响应转换器接口
*/
public interface Converter<F, T> {
T convert(F from) throws Exception;
}
}
// 使用示例
CustomRequest<MyData> request = new CustomRequest<>(
Request.Method.GET,
"https://api.example.com/data",
new Response.Listener<MyData>() {
@Override
public void onResponse(MyData response) {
// 处理转换后的响应
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 处理错误
}
},
new CustomRequest.Converter<NetworkResponse, MyData>() {
@Override
public MyData convert(NetworkResponse response) throws Exception {
// 实现自定义转换逻辑
String jsonString = new String(response.data);
return new Gson().fromJson(jsonString, MyData.class);
}
}
);
5.3 优先级处理
Volley支持为请求设置不同的优先级,高优先级的请求会优先处理:
// Request类中的Priority枚举
public enum Priority {
LOW,
NORMAL,
HIGH,
IMMEDIATE
}
// Request类的getPriority方法
public Priority getPriority() {
return Priority.NORMAL;
}
// Request类的setPriority方法
public final void setPriority(Priority priority) {
mPriority = priority;
}
// RequestQueue类的add方法,将请求添加到队列
public <T> Request<T> add(Request<T> request) {
// 将请求添加到请求集合中
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 标记请求已添加到队列
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// 如果请求不使用缓存,直接添加到网络队列
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// 对于使用缓存的请求,添加到缓存队列
mCacheQueue.add(request);
return request;
}
// PriorityBlockingQueue类,支持优先级的阻塞队列
public class PriorityBlockingQueue<E extends Comparable<? super E>> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// 队列内部使用的数组
private transient Object[] queue;
// 队列容量
private int capacity;
// 队列大小
private int size;
// 锁
private final ReentrantLock lock;
// 条件变量
private final Condition notEmpty;
// 比较器
private transient Comparator<? super E> comparator;
// 其他方法...
/**
* 将元素插入队列
*/
@Override
public void put(E e) {
offer(e); // 无界队列,不会阻塞
}
/**
* 获取并移除队列头部元素,如果队列为空则阻塞
*/
@Override
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (size == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
// 入队方法,会根据元素的优先级排序
private boolean offer(E x) {
if (x == null)
throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
try {
int n = size;
if (n >= queue.length)
tryGrow(queue, n);
siftUp(n, x);
size = n + 1;
notEmpty.signal();
} finally {
lock.unlock();
}
return true;
}
// 根据元素的比较器进行堆排序
private void siftUp(int k, E x) {
Comparator<? super E> cmp = comparator;
if (cmp != null)
siftUpUsingComparator(k, x, queue, cmp);
else
siftUpComparable(k, x, queue);
}
// 其他方法...
}
// CacheDispatcher类中从缓存队列获取请求
final Request<?> request = mCacheQueue.take();
// NetworkDispatcher类中从网络队列获取请求
request = mNetworkQueue.take();
5.4 响应拦截器
Volley允许添加响应拦截器,在响应到达应用层之前进行预处理:
// 定义响应拦截器接口
public interface ResponseInterceptor {
/**
* 拦截并处理响应
* @param request 原始请求
* @param response 响应
* @return 处理后的响应
*/
Response<?> intercept(Request<?> request, Response<?> response);
}
// 修改RequestQueue类以支持拦截器
public class RequestQueue {
// 响应拦截器列表
private final List<ResponseInterceptor> mResponseInterceptors = new ArrayList<>();
// 添加响应拦截器
public void addResponseInterceptor(ResponseInterceptor interceptor) {
mResponseInterceptors.add(interceptor);
}
// 分发响应时应用拦截器
private void postProcessResponse(Request<?> request, Response<?> response) {
Response<?> processedResponse = response;
for (ResponseInterceptor interceptor : mResponseInterceptors) {
processedResponse = interceptor.intercept(request, processedResponse);
if (processedResponse == null) {
// 如果拦截器返回null,停止处理
return;
}
}
// 分发处理后的响应
mDelivery.postResponse(request, processedResponse);
}
// 其他方法保持不变...
}
// 自定义响应拦截器示例
public class LoggingInterceptor implements ResponseInterceptor {
@Override
public Response<?> intercept(Request<?> request, Response<?> response) {
// 记录响应日志
Log.d("VolleyInterceptor", "Request: " + request.getUrl());
Log.d("VolleyInterceptor", "Response: " + (response.isSuccess() ? response.result : response.error));
// 返回原始响应或修改后的响应
return response;
}
}
// 使用示例
RequestQueue requestQueue = Volley.newRequestQueue(context);
requestQueue.addResponseInterceptor(new LoggingInterceptor());
六、Response响应处理的性能优化
6.1 线程池配置
Volley使用线程池来处理网络请求和响应,合理配置线程池可以提高性能:
// Volley类中创建RequestQueue的方法
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
// 创建缓存目录
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
// 如果没有提供HttpStack,根据API级别选择合适的实现
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
// 忽略异常
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// 对于API级别低于9的设备,使用HttpClient
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
// 创建网络实现
Network network = new BasicNetwork(stack);
// 创建RequestQueue,使用默认线程池配置
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
// RequestQueue类的构造函数
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
// RequestQueue类的start方法
public void start() {
// 停止任何正在运行的调度器
stop();
// 创建并启动缓存调度器
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// 创建并启动网络调度器
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
6.2 缓存策略优化
合理的缓存策略可以显著减少网络请求,提高应用性能:
// 设置请求的缓存策略
request.setShouldCache(true); // 启用缓存
// 自定义缓存时间
public class CustomRequest<T> extends Request<T> {
private final long mCacheTimeMs;
public CustomRequest(int method, String url, Response.Listener<T> listener,
Response.ErrorListener errorListener, long cacheTimeMs) {
super(method, url, errorListener);
mListener = listener;
mCacheTimeMs = cacheTimeMs;
}
@Override
public Priority getPriority() {
return Priority.NORMAL;
}
@Override
public Cache.Entry parseNetworkResponse(NetworkResponse response) {
Cache.Entry entry = super.parseNetworkResponse(response);
if (entry != null && mCacheTimeMs > 0) {
// 修改缓存的软过期时间
entry.softTtl = System.currentTimeMillis() + mCacheTimeMs;
}
return entry;
}
// 其他方法...
}
// 使用示例
CustomRequest<String> request = new CustomRequest<>(
Request.Method.GET,
"https://api.example.com/data",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// 处理响应
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 处理错误
}
},
30 * 1000 // 缓存30秒
);
6.3 批量响应处理
对于需要同时处理多个响应的场景,可以使用批量响应处理:
// 批量请求处理类
public class BatchRequestProcessor {
private final RequestQueue mRequestQueue;
private final Map<String, Request<?>> mRequests = new HashMap<>();
private final List<Response.Listener<Map<String, Object>>> mListeners = new ArrayList<>();
private final Map<String, Object> mResponses = new ConcurrentHashMap<>();
private int mTotalRequests = 0;
private int mCompletedRequests = 0;
private boolean mHasError = false;
public BatchRequestProcessor(RequestQueue requestQueue) {
mRequestQueue = requestQueue;
}
/**
* 添加请求到批量处理
*/
public <T> void addRequest(String key, Request<T> request) {
mRequests.put(key, request);
mTotalRequests++;
// 设置请求的监听器
request.setListener(new Response.Listener<T>() {
@Override
public void onResponse(T response) {
synchronized (BatchRequestProcessor.this) {
mResponses.put(key, response);
mCompletedRequests++;
// 检查是否所有请求都已完成
if (mCompletedRequests == mTotalRequests && !mHasError) {
notifyListeners();
}
}
}
});
request.setErrorListener(new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
synchronized (BatchRequestProcessor.this) {
mHasError = true;
// 取消所有未完成的请求
for (Map.Entry<String, Request<?>> entry : mRequests.entrySet()) {
if (!mResponses.containsKey(entry.getKey())) {
entry.getValue().cancel();
}
}
// 通知监听器发生错误
for (Response.Listener<Map<String, Object>> listener : mListeners) {
listener.onResponse(null); // 返回null表示发生错误
}
mListeners.clear();
}
}
});
}
/**
* 添加响应监听器
*/
public void addListener(Response.Listener<Map<String, Object>> listener) {
mListeners.add(listener);
}
/**
* 执行批量请求
*/
public void execute() {
for (Request<?> request : mRequests.values()) {
mRequestQueue.add(request);
}
}
/**
* 通知所有监听器
*/
private void notifyListeners() {
for (Response.Listener<Map<String, Object>> listener : mListeners) {
listener.onResponse(mResponses);
}
mListeners.clear();
}
}
// 使用示例
BatchRequestProcessor batchProcessor = new BatchRequestProcessor(requestQueue);
// 添加多个请求
batchProcessor.addRequest("request1", stringRequest1);
batchProcessor.addRequest("request2", jsonRequest2);
batchProcessor.addRequest("request3", imageRequest3);
// 添加监听器
batchProcessor.addListener(new Response.Listener<Map<String, Object>>() {
@Override
public void onResponse(Map<String, Object> responses) {
if (responses != null) {
// 处理所有成功的响应
String response1 = (String) responses.get("request1");
JSONObject response2 = (JSONObject) responses.get("request2");
Bitmap response3 = (Bitmap) responses.get("request3");
// 更新UI
} else {
// 处理错误
}
}
});
// 执行批量请求
batchProcessor.execute();
6.4 响应解析优化
优化响应解析过程可以减少CPU使用,提高应用响应速度:
// 使用流式解析替代一次性解析大JSON
public class StreamJsonRequest extends Request<JSONArray> {
private final Response.Listener<JSONArray> mListener;
public StreamJsonRequest(int method, String url, Response.Listener<JSONArray> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
@Override
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
try {
// 使用BufferedInputStream提高读取效率
ByteArrayInputStream bis = new ByteArrayInputStream(response.data);
BufferedInputStream bis = new BufferedInputStream(bis);
// 使用JSONTokener进行流式解析
JSONTokener tokener = new JSONTokener(new InputStreamReader(bis));
JSONArray jsonArray = new JSONArray();
// 假设响应是JSON数组
if (tokener.nextValue() instanceof JSONArray) {
jsonArray = (JSONArray) tokener.nextValue();
}
return Response.success(jsonArray, HttpHeaderParser.parseCacheHeaders(response));
} catch (JSONException e) {
return Response.error(new ParseError(e));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(JSONArray response) {
mListener.onResponse(response);
}
}
// 优化图片解析
public class OptimizedImageRequest extends ImageRequest {
public OptimizedImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth,
int maxHeight, ScaleType scaleType, Config decodeConfig,
Response.ErrorListener errorListener) {
super(url, listener, maxWidth, maxHeight, scaleType, decodeConfig, errorListener);
}
@Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
// 同步锁,防止同时进行多个图片解码操作
synchronized (sDecodeLock) {
try {
return doParse(response);
} catch (OutOfMemoryError e) {
// 内存不足时,尝试降低图片质量
VolleyLog.e("Caught OOM for %d byte image, trying to decode with lower quality",
response.data.length);
try {
// 创建新的Options,设置inSampleSize为2
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
options.inPreferredConfig = Bitmap.Config.RGB_565;
// 再次尝试解码
Bitmap bitmap = BitmapFactory.decodeByteArray(
response.data, 0, response.data.length, options);
if (bitmap == null) {
return Response.error(new ParseError(e));
} else {
// 调整图片尺寸
if (bitmap.getWidth() > getMaxWidth() || bitmap.getHeight() > getMaxHeight()) {
Bitmap resizedBitmap = Bitmap.createScaledBitmap(
bitmap, getMaxWidth(), getMaxHeight(), true);
bitmap.recycle();
bitmap = resizedBitmap;
}
return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
}
} catch (OutOfMemoryError e2) {
VolleyLog.e("Second OOM attempt for %d byte image, url=%s",
response.data.length, getUrl());
return Response.error(new ParseError(e2));
}
}
}
}
}
七、与其他组件的协同工作
7.1 与Request的协同
Response处理机制与Request紧密配合,形成完整的网络请求流程:
// Request类的关键方法
public abstract class Request<T> implements Comparable<Request<T>> {
// 请求优先级
private Priority mPriority = Priority.NORMAL;
// 请求监听器
private final Response.Listener<T> mListener;
// 错误监听器
private final Response.ErrorListener mErrorListener;
// 请求是否已取消
private boolean mCanceled = false;
// 响应是否已分发
private boolean mResponseDelivered = false;
// 重试策略
private RetryPolicy mRetryPolicy;
// 缓存键
private String mCacheKey;
// 其他成员变量...
/**
* 构造函数
*/
public Request(int method, String url, Response.ErrorListener listener) {
mMethod = method;
mUrl = url;
mErrorListener = listener;
setRetryPolicy(new DefaultRetryPolicy());
}
/**
* 获取请求方法
*/
public int getMethod() {
return mMethod;
}
/**
* 获取请求URL
*/
public String getUrl() {
return mUrl;
}
/**
* 获取缓存键
*/
public String getCacheKey() {
return mCacheKey != null ? mCacheKey : mUrl;
}
/**
* 设置缓存键
*/
public void setCacheKey(String cacheKey) {
mCacheKey = cacheKey;
}
/**
* 判断请求是否应该使用缓存
*/
public boolean shouldCache() {
return true;
}
/**
* 获取请求优先级
*/
public Priority getPriority() {
return mPriority;
}
/**
* 设置请求优先级
*/
public void setPriority(Priority priority) {
mPriority = priority;
}
/**
* 获取超时时间
*/
public int getTimeoutMs() {
return mRetryPolicy.getCurrentTimeout();
}
/**
* 获取重试策略
*/
public RetryPolicy getRetryPolicy() {
return mRetryPolicy;
}
/**
* 设置重试策略
*/
public void setRetryPolicy(RetryPolicy retryPolicy) {
mRetryPolicy = retryPolicy;
}
/**
* 取消请求
*/
public void cancel() {
mCanceled = true;
}
/**
* 判断请求是否已取消
*/
public boolean isCanceled() {
return mCanceled;
}
/**
* 解析网络响应,由子类实现
*/
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
/**
* 分发响应
*/
protected void deliverResponse(T response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
/**
* 分发错误
*/
public void deliverError(VolleyError error) {
mResponseDelivered = true;
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
/**
* 判断响应是否已分发
*/
public boolean hasHadResponseDelivered() {
return mResponseDelivered;
}
/**
* 比较请求优先级
*/
@Override
public int compareTo(Request<T> other) {
Priority left = this.getPriority();
Priority right = other.getPriority();
// 高优先级的请求排在前面
return left == right ?
this.mSequence - other.mSequence :
right.ordinal() - left.ordinal();
}
// 其他方法...
}
7.2 与RequestQueue的协同
RequestQueue负责管理请求的调度和响应的分发:
// RequestQueue类的关键方法
public class RequestQueue {
// 缓存队列
private final PriorityBlockingQueue<Request<?>> mCacheQueue =
new PriorityBlockingQueue<Request<?>>();
// 网络队列
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
new PriorityBlockingQueue<Request<?>>();
// 缓存实现
private final Cache mCache;
// 网络实现
private final Network mNetwork;
// 响应分发器
private final ResponseDelivery mDelivery;
// 缓存调度器
private CacheDispatcher mCacheDispatcher;
// 网络调度器数组
private NetworkDispatcher[] mDispatchers;
// 当前请求集合
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
// 序列生成器
private AtomicInteger mSequenceGenerator = new AtomicInteger();
/**
* 构造函数
*/
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
/**
* 启动请求队列
*/
public void start() {
// 停止任何正在运行的调度器
stop();
// 创建并启动缓存调度器
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// 创建并启动网络调度器
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
/**
* 停止请求队列
*/
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
/**
* 添加请求到队列
*/
public <T> Request<T> add(Request<T> request) {
// 将请求添加到请求集合中
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 标记请求已添加到队列
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// 如果请求不使用缓存,直接添加到网络队列
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// 对于使用缓存的请求,添加到缓存队列
mCacheQueue.add(request);
return request;
}
/**
* 从队列中移除请求
*/
public void cancelAll(RequestFilter filter) {
synchronized (mCurrentRequests) {
for (Request<?> request : mCurrentRequests) {
if (filter.apply(request)) {
request.cancel();
}
}
}
}
/**
* 获取序列数
*/
public int getSequenceNumber() {
return mSequenceGenerator.incrementAndGet();
}
// 其他方法...
}
7.3 与Cache的协同
响应处理机制与缓存系统协同工作,实现数据的缓存和读取:
// Cache接口定义
public interface Cache {
/**
* 从缓存中获取条目
*/
public Entry get(String key);
/**
* 将条目放入缓存
*/
public void put(String key, Entry entry);
/**
* 刷新缓存条目
*/
public void invalidate(String key, boolean fullExpire);
/**
* 移除缓存条目
*/
public void remove(String key);
/**
* 清空缓存
*/
public void clear();
/**
* 缓存条目类
*/
public static class Entry {
// 缓存数据
public byte[] data;
// ETag
public String etag;
// 服务器时间
public long serverDate;
// 软过期时间
public long softTtl;
// 硬过期时间
public long ttl;
// 响应头
public Map<String, String> responseHeaders = Collections.emptyMap();
/**
* 判断缓存是否已过期
*/
public boolean isExpired() {
return this.ttl < System.currentTimeMillis();
}
/**
* 判断缓存是否需要刷新
*/
public boolean refreshNeeded() {
return this.softTtl < System.currentTimeMillis();
}
}
}
// DiskBasedCache类的实现
public class DiskBasedCache implements Cache {
// 缓存目录
private final File mRootDirectory;
// 缓存最大大小(字节)
private final int mMaxCacheSizeInBytes;
// 当前缓存大小(字节)
private long mTotalSize = 0;
// 缓存条目映射
private final HashMap<String, CacheHeader> mEntries = new HashMap<String, CacheHeader>();
// 其他成员变量...
/**
* 构造函数
*/
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {
mRootDirectory = rootDirectory;
mMaxCacheSizeInBytes = maxCacheSizeInBytes;
}
/**
* 初始化缓存
*/
@Override
public synchronized void initialize() {
if (!mRootDirectory.exists()) {
if (!mRootDirectory.mkdirs()) {
VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());
}
return;
}
// 列出所有缓存文件
File[] files = mRootDirectory.listFiles();
if (files == null) {
return;
}
// 加载所有缓存条目
for (File file : files) {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
CacheHeader entry = CacheHeader.readHeader(fis);
entry.size = file.length();
putEntry(entry.key, entry);
} catch (IOException e) {
if (file != null) {
file.delete();
}
} finally {
// 关闭文件流
closeQuietly(fis);
}
}
}
/**
* 从缓存中获取条目
*/
@Override
public synchronized Entry get(String key) {
CacheHeader entry = mEntries.get(key);
// 如果条目不存在,返回null
if (entry == null) {
return null;
}
// 获取缓存文件
File file = getFileForKey(key);
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
// 验证缓存文件的长度是否正确
CountingInputStream cis = new CountingInputStream(fis);
CacheHeader.readHeader(cis); // 读取并丢弃头部
// 计算剩余字节数(即数据部分)
byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead));
return entry.toCacheEntry(data);
} catch (IOException e) {
// 读取文件时出错,删除该文件
remove(key);
return null;
} finally {
closeQuietly(fis);
}
}
/**
* 将条目放入缓存
*/
@Override
public synchronized void put(String key, Entry entry) {
// 确保有足够的空间
pruneIfNeeded(entry.data.length);
// 获取缓存文件
File file = getFileForKey(key);
FileOutputStream fos = null;
try {
// 将条目写入文件
fos = new FileOutputStream(file);
CacheHeader header = new CacheHeader(key, entry);
header.writeHeader(fos);
fos.write(entry.data);
fos.flush();
// 更新缓存条目
putEntry(key, header);
return;
} catch (IOException e) {
// 写入文件时出错
} finally {
closeQuietly(fos);
}
// 如果写入失败,删除文件
boolean deleted = file.delete();
if (!deleted) {
VolleyLog.d("Could not clean up file %s", file.getAbsolutePath());
}
}
// 其他方法...
}
7.4 与Network的协同
响应处理机制与网络层协同工作,实现数据的网络传输:
// Network接口定义
public interface Network {
/**
* 执行网络请求
*/
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
// BasicNetwork类的实现
public class BasicNetwork implements Network {
protected static final boolean DEBUG = VolleyLog.DEBUG;
// 每4KB读取一次
private static final int DEFAULT_POOL_SIZE = 4096;
// HTTP栈
protected final HttpStack mHttpStack;
// 缓冲区池
protected final ByteArrayPool mPool;
/**
* 构造函数
*/
public BasicNetwork(HttpStack httpStack) {
// 如果使用默认的缓冲区池大小
this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
}
/**
* 构造函数
*/
public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
mHttpStack = httpStack;
mPool = pool;
}
/**
* 执行网络请求
*/
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
// 循环处理重定向
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
// 准备请求头
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
// 执行HTTP请求
httpResponse = mHttpStack.performRequest(request, headers);
// 获取HTTP状态码
final int statusCode = httpResponse.getStatusCode();
// 获取响应头
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// 如果状态码是304(Not Modified)
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
// 处理304状态码
Cache.Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null,
responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
// 返回缓存的响应
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED,
entry.data, responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
// 读取响应数据
if (httpResponse.getEntity() != null) {
responseContents = entityToBytes(httpResponse.getEntity());
} else {
// 对于没有响应体的请求,创建一个空的响应体
responseContents = new byte[0];
}
// 计算网络请求耗时
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
// 记录请求统计信息
logSlowRequests(requestLifetime, request, responseContents, statusCode);
// 如果状态码不是200,抛出异常
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
// 返回网络响应
return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
SystemClock.elapsedRealtime() - requestStart);
} catch (SocketTimeoutException e) {
// 处理超时异常
attemptRetryOnException("socket", request, new TimeoutError());
} catch (MalformedURLException e) {
// 处理URL格式错误
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
// 处理IO异常
int statusCode = 0;
NetworkResponse networkResponse = null;
// 尝试获取HTTP状态码
if (httpResponse != null) {
statusCode = httpResponse.getStatusCode();
} else {
throw new NoConnectionError(e);
}
// 记录错误日志
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
// 处理服务器错误
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
// 处理特定的HTTP状态码
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED ||
statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode == HttpURLConnection.HTTP_MOVED_PERM ||
statusCode == HttpURLConnection.HTTP_MOVED_TEMP ||
statusCode == HttpURLConnection.HTTP_SEE_OTHER ||
statusCode == 307) {
// 处理重定向
String newUrl = responseHeaders.get("Location");
if (newUrl == null) {
// 如果没有Location头,抛出异常
throw new VolleyError(networkResponse);
}
// 更新请求URL并继续循环
request.setRedirectUrl(newUrl);
continue;
} else {
// 其他错误状态码
throw new ServerError(networkResponse);
}
} else {
// 没有响应内容的错误
attemptRetryOnException("network", request, new NetworkError(e));
}
}
}
}
// 其他方法...
}
八、响应处理的安全性考量
8.1 数据验证与过滤
在响应处理过程中,对服务器返回的数据进行严格验证和过滤是保障应用安全的重要手段。Volley框架虽然不直接提供复杂的验证逻辑,但开发者可以在响应解析阶段添加验证代码。
// 在JsonObjectRequest的解析中添加数据验证
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
JSONObject jsonObject = new JSONObject(jsonString);
// 验证返回数据是否包含必要字段
if (!jsonObject.has("status") || !jsonObject.has("data")) {
throw new JSONException("Invalid response format");
}
// 对数据进行类型检查
if (!jsonObject.get("status").equals("success")) {
// 根据错误状态码进一步处理
int errorCode = jsonObject.optInt("error_code", -1);
String errorMessage = jsonObject.optString("error_message", "Unknown error");
throw new VolleyError(new ServerError(new NetworkResponse(
500,
errorMessage.getBytes(),
response.headers,
false,
0
)));
}
return Response.success(jsonObject, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
8.2 防止数据泄露
在处理敏感数据响应时,需避免数据泄露。例如,对包含用户隐私信息(如身份证号、银行卡号等)的响应,应进行加密存储和传输。同时,在响应解析后,避免在日志中打印完整的敏感数据。
// 对敏感数据进行加密存储
public class SensitiveDataRequest extends JsonObjectRequest {
private final AESUtils aesUtils; // 假设AESUtils是自定义的AES加密工具类
public SensitiveDataRequest(int method, String url, JSONObject jsonRequest,
Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
aesUtils = new AESUtils(); // 初始化加密工具
}
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
JSONObject jsonObject = new JSONObject(jsonString);
// 假设数据在"data"字段中
if (jsonObject.has("data")) {
JSONObject dataObject = jsonObject.getJSONObject("data");
String sensitiveData = dataObject.optString("sensitive_info", "");
// 对敏感数据进行加密
String encryptedData = aesUtils.encrypt(sensitiveData);
dataObject.put("sensitive_info", encryptedData);
}
return Response.success(jsonObject, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
8.3 防范网络攻击
Volley响应处理还需防范常见的网络攻击,如SQL注入、XSS攻击等。对于包含用户输入的响应数据,在用于数据库操作或UI展示前,必须进行严格的转义和过滤。
// 对用于数据库操作的响应数据进行转义
public class DatabaseBoundRequest extends JsonObjectRequest {
public DatabaseBoundRequest(int method, String url, JSONObject jsonRequest,
Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
}
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
JSONObject jsonObject = new JSONObject(jsonString);
if (jsonObject.has("query_data")) {
String queryData = jsonObject.getString("query_data");
// 使用SQLiteDatabase的escapeString方法进行转义
String escapedData = SQLiteDatabase.openOrCreateDatabase("", null).escapeString(queryData);
jsonObject.put("query_data", escapedData);
}
return Response.success(jsonObject, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
九、响应处理的扩展性设计
9.1 自定义响应解析器
Volley允许开发者通过实现ResponseParser接口来自定义响应解析逻辑,以适应特殊的数据格式或业务需求。
// 自定义XML响应解析器
public class XmlResponseParser implements ResponseParser {
@Override
public Response<?> parseNetworkResponse(NetworkResponse response) {
try {
String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(xmlString)));
// 解析XML文档,提取所需数据
NodeList nodeList = document.getElementsByTagName("data");
if (nodeList.getLength() > 0) {
Node node = nodeList.item(0);
String parsedData = node.getTextContent();
return Response.success(parsedData, HttpHeaderParser.parseCacheHeaders(response));
} else {
throw new XmlPullParserException("No data node found");
}
} catch (UnsupportedEncodingException | XmlPullParserException | ParserConfigurationException | SAXException e) {
return Response.error(new ParseError(e));
}
}
}
// 使用自定义解析器的请求
public class XmlRequest extends Request<String> {
private final Response.Listener<String> listener;
public XmlRequest(int method, String url, Response.Listener<String> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.listener = listener;
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
ResponseParser parser = new XmlResponseParser();
return (Response<String>) parser.parseNetworkResponse(response);
}
@Override
protected void deliverResponse(String response) {
listener.onResponse(response);
}
}
9.2 插件式响应拦截器
除了前面提到的响应拦截器,还可以通过更灵活的插件机制来管理拦截器,方便添加、删除和修改拦截逻辑。
// 定义响应拦截器插件接口
public interface ResponseInterceptorPlugin {
Response<?> intercept(Request<?> request, Response<?> response);
}
// 管理拦截器插件的类
public class InterceptorPluginManager {
private final List<ResponseInterceptorPlugin> plugins = new ArrayList<>();
public void registerPlugin(ResponseInterceptorPlugin plugin) {
plugins.add(plugin);
}
public void unregisterPlugin(ResponseInterceptorPlugin plugin) {
plugins.remove(plugin);
}
public Response<?> processResponse(Request<?> request, Response<?> response) {
Response<?> processedResponse = response;
for (ResponseInterceptorPlugin plugin : plugins) {
processedResponse = plugin.intercept(request, processedResponse);
if (processedResponse == null) {
break;
}
}
return processedResponse;
}
}
// 修改RequestQueue以使用插件式拦截器
public class PluginBasedRequestQueue {
private final InterceptorPluginManager pluginManager;
// 其他RequestQueue相关成员变量和方法
public PluginBasedRequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
// 初始化其他成员变量
pluginManager = new InterceptorPluginManager();
}
public void registerInterceptorPlugin(ResponseInterceptorPlugin plugin) {
pluginManager.registerPlugin(plugin);
}
public void unregisterInterceptorPlugin(ResponseInterceptorPlugin plugin) {
pluginManager.unregisterPlugin(plugin);
}
private void postProcessResponse(Request<?> request, Response<?> response) {
Response<?> processedResponse = pluginManager.processResponse(request, response);
mDelivery.postResponse(request, processedResponse);
}
}
9.3 动态响应处理策略
根据不同的网络环境、设备状态或用户配置,动态调整响应处理策略。例如,在弱网环境下降低图片质量,减少数据传输量。
// 根据网络状态调整图片请求策略
public class AdaptiveImageRequest extends ImageRequest {
private final ConnectivityManager connectivityManager;
public AdaptiveImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth,
int maxHeight, ScaleType scaleType, Config decodeConfig,
Response.ErrorListener errorListener, Context context) {
super(url, listener, maxWidth, maxHeight, scaleType, decodeConfig, errorListener);
connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
@Override
protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
// 如果是移动网络,降低图片质量
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeByteArray(response.data, 0, response.data.length, options);
return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
} else {
return super.parseNetworkResponse(response);
}
}
}
十、与其他网络库的对比分析
10.1 与OkHttp的响应处理对比
OkHttp的响应处理侧重于通过Call和Callback机制实现异步操作,并且提供了强大的拦截器链用于请求和响应的处理。而Volley的响应处理更紧密地与Android应用的UI线程集成,在缓存管理和请求队列调度上有独特的设计。
// OkHttp的异步响应处理示例
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
// 处理失败
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (response.isSuccessful()) {
String data = response.body().string();
// 解析和处理数据
} else {
// 处理错误响应
}
}
});
对比之下,Volley通过RequestQueue管理请求,ResponseDelivery实现线程切换,在响应缓存的自动处理和与Android组件的集成方面更具优势。
10.2 与Retrofit的响应处理对比
Retrofit基于OkHttp,主要通过接口定义和注解来简化网络请求,其响应处理依赖于Converter和CallAdapter。而Volley的响应处理更注重底层的网络请求调度和响应解析的灵活性。
// Retrofit的响应处理示例
public interface ApiService {
@GET("data")
Call<MyData> getData();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
Call<MyData> call = apiService.getData();
call.enqueue(new Callback<MyData>() {
@Override
public void onResponse(Call<MyData> call, Response<MyData> response) {
if (response.isSuccessful()) {
MyData data = response.body();
// 处理数据
} else {
// 处理错误
}
}
@Override
public void onFailure(Call<MyData> call, Throwable t) {
// 处理失败
}
});
Volley的响应处理允许开发者更直接地控制请求和响应的各个环节,在小型项目或对性能优化有特定需求的场景中,可能比Retrofit更轻量和灵活。
10.3 优势与劣势总结
Volley响应处理的优势在于:
- 与Android系统深度集成,方便在UI线程处理响应
- 内置强大的缓存管理机制
- 灵活的请求队列和优先级调度
- 易于扩展的响应解析和拦截机制
然而,Volley也存在一些劣势:
- 相比OkHttp和Retrofit,在复杂网络场景下的扩展性稍弱
- 对现代HTTP/2等新特性的支持不如专门的网络库
- 代码结构相对复杂,学习成本较高
通过对Volley响应处理机制多维度、深层次的分析,相信开发者能够更透彻地掌握其原理与应用。如果在实际开发中有遇到特定问题,或想了解更多优化、扩展方向,欢迎与我交流。