访问网络是我们在开发Android应用过程中常常会需要用到,框架层给我们提供HTTPURLConnection可以认为是对网络操作最原子的一个操作,我们只需要按照接口的设定传入参数就可以返回流对象。Volley做为一个框架,它不仅包含了最核心的网络操作之外,还提供了缓存和异步请求队列的功能,也就是做了Cache大部分的工作,用户在使用的过程中就不需要过多的考虑如何做缓存等功能,下面我根据源码和自己的理解和读者一起走进Volley的世界。
Volley整体的架构图:
不管是任何框架或者是任何一个模块,其核心功能都可以高级抽象为:干什么,需要什么,得到什么。回到Volley,其实际上就演变成,操作网络,网络请求参数,操作结果,在Volley中的源码体现在:
public interface Network {
NetworkResponse performRequest(Request> var1) throws VolleyError;
}
public interface HttpStack {
HttpResponse performRequest(Request> var1, Map var2) throws IOException, AuthFailureError;
}
performRequest 可以抽象出整体的网络核心。所以Request表示网络请求的基类,NetworkResponse表示执行网络返回的结果。我们在使用HttpUrlConnection的时候是
URL url = new URL(urlString); //URL对象
conn = (HttpURLConnection)url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("GET");
is = conn.getInputStream();
url中携带了参数,HttpUrlConnection则代表了整个网络操作的动作,返回is流对象为操作的结果。
Request可以将其认为一条请求,而这条请求当中不仅包含了网络中需要携带的参数信息,还为请求添加一些可以约束的条件。例如源码中重要的属性:
private final MarkerLog mEventLog;
private final int mMethod; // 使用的方法,POST/GET
private String mUrl; // 请求地址
private final ErrorListener mErrorListener; // 错误回调
private Integer mSequence; //
private RequestQueue mRequestQueue; // 关联到的请求队列
private boolean mShouldCache; // 是否需要缓存
private boolean mCanceled; // 是否已经被取消
private boolean mResponseDelivered; // 是否已经被提交
private long mRequestBirthTime; // 请求被创建的时刻
private static final long SLOW_REQUEST_THRESHOLD_MS = 3000L;
private RetryPolicy mRetryPolicy; // 重发代理
private Entry mCacheEntry; // 键值对属性
private Object mTag; // tag
把请求封装为一个对象,实体数据。
BasicNetwork实现Network接口,它实现的方法体:
public NetworkResponse performRequest(Request> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while(true) {
HttpResponse httpResponse = null;
Object responseContents = null;
HashMap responseHeaders = new HashMap();
try {
HashMap e = new HashMap();
this.addCacheHeaders(e, request.getCacheEntry());
httpResponse = this.mHttpStack.performRequest(request, e);
StatusLine statusCode1 = httpResponse.getStatusLine();
int networkResponse1 = statusCode1.getStatusCode();
Map responseHeaders1 = convertHeaders(httpResponse.getAllHeaders());
if(networkResponse1 != 304) {
byte[] responseContents1;
if(httpResponse.getEntity() != null) {
responseContents1 = this.entityToBytes(httpResponse.getEntity());
} else {
responseContents1 = new byte[0];
}
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
this.logSlowRequests(requestLifetime, request, responseContents1, statusCode1);
if(networkResponse1 >= 200 && networkResponse1 <= 299) {
return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false);
}
throw new IOException();
}
return new NetworkResponse(304, request.getCacheEntry() == null?null:request.getCacheEntry().data, responseHeaders1, true);
} catch (Exception var12) {
boolean statusCode = false;
NetworkResponse networkResponse = null;
if(httpResponse == null) {
throw new NoConnectionError(var15);
}
int statusCode2 = httpResponse.getStatusLine().getStatusCode();
VolleyLog.e("Unexpected response code %d for %s", new Object[]{Integer.valueOf(statusCode2), request.getUrl()});
if(responseContents == null) {
throw new NetworkError(networkResponse);
}
networkResponse = new NetworkResponse(statusCode2, (byte[])responseContents, responseHeaders, false);
if(statusCode2 != 401 && statusCode2 != 403) {
throw new ServerError(networkResponse);
}
attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
}
}
}
源码中
mHttpStack.performRequest(request, e),为何要单独另起一个HttpStack来执行?这就是一种策略模式,BasicNetwork代表的整体网络操作的一个抽象,即BasicNetwork中的performRequest抽象为执行这个方法,我将给你返回一个结果,但是执行的操作可能不只一种操作方式,而是用策略模式去让上层决定该以何种方式来执行本次操作,方便接口的扩展。接触设计模式比较少的读者朋友建议多去学习体会设计模式,因为设计模式不仅仅可以提高工作效率,而且使你的代码看起来更加整洁,富有扩展性。执行完之后获取得到一个HTTPResponse响应流对象,这时候将执行结果包装到Response对象中,网络操作部分的过程就结束了。
上面谈到的策略模式,具体实现用到的策略执行performRequest操作的是HttpStack的实现类,其中一个子类HttpClientStack,我们看一下它的执行过程:
public HttpResponse performRequest(Request> request, Map additionalHeaders) throws IOException, AuthFailureError {
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
addHeaders(httpRequest, additionalHeaders);
addHeaders(httpRequest, request.getHeaders());
this.onPrepareRequest(httpRequest);
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
return this.mClient.execute(httpRequest);
}
可以看到,实际上真正访问网络就是使用HttpClient,这只是一个具体的策略实现类,把参数头部信息携带进去execute后则得到响应流对象。createHttpRequest方法则解析request中携带的一些约束信息构成一个执行环境和配置信息,然后就可以真正开始执行网络了。
private final Map>> mWaitingRequests; // 等待执行的请求
private final Set> mCurrentRequests; // 当前正在执行的请求
private final PriorityBlockingQueue> mCacheQueue; // 带有权重的请求缓存
private final PriorityBlockingQueue> mNetworkQueue; // 带有权重的请求
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
private final Cache mCache;
private final Network mNetwork; // 针对每个Request执行的实际网络操作
private final ResponseDelivery mDelivery; // 结果处理器
private NetworkDispatcher[] mDispatchers; // 任务执行分发器
private CacheDispatcher mCacheDispatcher; // 缓存分发器
在实际使用过程中,我们使用Volley.newRequestQueue创建一个任务调度处理器RequestQueue,并且传入一个BasicNetwork实力对象,启用start方法开启调度器的工作,start源码如下:
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
public void stop() {
if(this.mCacheDispatcher != null) {
this.mCacheDispatcher.quit();
}
for(int i = 0; i < this.mDispatchers.length; ++i) {
if(this.mDispatchers[i] != null) {
this.mDispatchers[i].quit();
}
}
}
NetworkDispatcher单条任务器继承于Thread,这条线程管理一个任务队列,run方法体源码:
public void run() {
Process.setThreadPriority(10);
while(true) {
Request request;
while(true) {
try {
request = (Request)this.mQueue.take(); // RequestQueue中mNetworkQueue
break;
} catch (InterruptedException var4) {
if(this.mQuit) {
return;
}
}
}
try {
request.addMarker("network-queue-take");
if(request.isCanceled()) {
request.finish("network-discard-cancelled");
} else {
this.addTrafficStatsTag(request);
NetworkResponse e = this.mNetwork.performRequest(request);
request.addMarker("network-http-complete");
if(e.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
} else {
Response response = request.parseNetworkResponse(e);
request.addMarker("network-parse-complete");
if(request.shouldCache() && response.cacheEntry != null) {
this.mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
this.mDelivery.postResponse(request, response);
}
}
} catch (VolleyError var5) {
this.parseAndDeliverNetworkError(request, var5);
} catch (Exception var6) {
VolleyLog.e(var6, "Unhandled exception %s", new Object[]{var6.toString()});
this.mDelivery.postError(request, new VolleyError(var6));
}
}
}
while(true)不断检测当前的队列,此时当队列中一有请求的时候就可以及时的被发出去。上文提到的ResponseDelivery,该类则负责执行结果的接收。
public void postResponse(Request> request, Response> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));
}
ResponseDeliveryRunnable.run()
public void run() {
if(this.mRequest.isCanceled()) {
this.mRequest.finish("canceled-at-delivery");
} else {
if(this.mResponse.isSuccess()) {
this.mRequest.deliverResponse(this.mResponse.result);
} else {
this.mRequest.deliverError(this.mResponse.error);
}
if(this.mResponse.intermediate) {
this.mRequest.addMarker("intermediate-response");
} else {
this.mRequest.finish("done");
}
if(this.mRunnable != null) {
this.mRunnable.run();
}
}
}
所以在我们创建一个请求的时候,通过传入结果回调Listener,即可得到处理后的结果。