BasicNetwork类实现了Network 接口,而Network接口如下:
package com.android.volley;
/**
* An interface for performing requests.
*/
public interface Network {
/**
* Performs the specified request.
* @param request Request to process
* @return A {@link NetworkResponse} with data and caching metadata; will never be null
* @throws VolleyError on errors
*/
NetworkResponse performRequest(Request request) throws VolleyError;
}
BasicNetwork类在performRequest 将Request发送出去,得到NetworkResponse。看一看BasicNetwork的构造方法如下:
/**
* @param httpStack HTTP stack to be used
* @param pool a buffer pool that improves GC performance in copy operations
*/
public BasicNetwork(BaseHttpStack httpStack, ByteArrayPool pool) {
mBaseHttpStack = httpStack;
// Populate mHttpStack for backwards compatibility, since it is a protected field. However,
// we won't use it directly here, so clients which don't access it directly won't need to
// depend on Apache HTTP.
mHttpStack = httpStack;
mPool = pool;
}
实现BasicNetwork 的语句为:
BasicNetwork network = new BasicNetwork(new HurlStack());
其中 HurlStack 继承了BaseHttpStack 类,而BaseHttpStack类实现了HttpStack接口:
/**
* An HTTP stack abstraction.
*
* @deprecated This interface should be avoided as it depends on the deprecated Apache HTTP library.
* Use {@link BaseHttpStack} to avoid this dependency. This class may be removed in a future
* release of Volley.
*/
@Deprecated
public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
*
* A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
* and the Content-Type header is set to request.getPostBodyContentType().
*
* @param request the request to perform
* @param additionalHeaders additional headers to be sent together with
* {@link Request#getHeaders()}
* @return the HTTP response
*/
HttpResponse performRequest(Request request, Map additionalHeaders)
throws IOException, AuthFailureError;
}
其实真正进行Http请求访问的是 HurlStack 类,而BasicNetwork 类将其返回的HttpResponse 包装成为NetworkResponse。BasicNetwork类的performRequest方法代码如下:
@Override
public NetworkResponse performRequest(Request request) throws VolleyError {
//获取请求时间
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
List responseHeaders = Collections.emptyList();
try {
// Gather headers. 从request获取请求头
Map additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
//通过HttpStack对象发送Request得到HttpResponse对象。
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
//得到响应状态码
int statusCode = httpResponse.getStatusCode();
//得到响应头
responseHeaders = httpResponse.getHeaders();
// Handle cache validation. 当返回状态码为304时,返回状态为304的NetworkResponse对象
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) { // HTTP 状态码 304:Not Modified。
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null, true,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
}
// Combine cached and response headers so the response will be complete.
List combinedHeaders = combineHeaders(responseHeaders, entry);
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data,
true, SystemClock.elapsedRealtime() - requestStart, combinedHeaders);
}
// Some responses such as 204s do not have content. We must check.
//获取响应内容存入responseContents
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
responseContents =
inputStreamToBytes(inputStream, httpResponse.getContentLength());
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
responseContents = new byte[0];
}
// if the request is slow, log it. 得到请求花费的时间时间
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusCode);
//如果状态码不正确,抛出异常
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
//如果一切正确返回 NetworkResponse对象
return new NetworkResponse(statusCode, responseContents, false,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
} catch (SocketTimeoutException e) {
//连接超时处理
attemptRetryOnException("socket", request, new TimeoutError());
} catch (MalformedURLException e) {
//异常处理
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
//IOException异常处理
int statusCode;
if (httpResponse != null) {
statusCode = httpResponse.getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
NetworkResponse networkResponse;
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents, false,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED || //HTTP 状态码 401:Unauthorized。
statusCode == HttpURLConnection.HTTP_FORBIDDEN) { //HTTP 状态码 403:Forbidden。
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode >= 400 && statusCode <= 499) {
// Don't retry other client errors.
throw new ClientError(networkResponse);
} else if (statusCode >= 500 && statusCode <= 599) {
if (request.shouldRetryServerErrors()) {
attemptRetryOnException("server",
request, new ServerError(networkResponse));
} else {
throw new ServerError(networkResponse);
}
} else {
// 3xx? No reason to retry.
throw new ServerError(networkResponse);
}
} else {
attemptRetryOnException("network", request, new NetworkError());
}
}
}
}
接下来来看一看HttpStack类的executeRequest方法:
@Override
public HttpResponse executeRequest(Request request, Map additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
HashMap map = new HashMap<>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if (mUrlRewriter != null) {
String rewritten = mUrlRewriter.rewriteUrl(url);
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
/**
* 通过在 URL 上调用 openConnection 方法创建连接对象。
处理设置参数和一般请求属性。
使用 connect 方法建立到远程对象的实际连接。
远程对象变为可用。远程对象的头字段和内容变为可访问。
*/
URL parsedUrl = new URL(url);
//调用Url的openConnection 方法得到HttpURLConnection连接对象
HttpURLConnection connection = openConnection(parsedUrl, request);
//添加请求头
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
//设置请求方法和请求参数
setConnectionParametersForRequest(connection, request);
// Initialize HttpResponse with data from the HttpURLConnection.
//得到响应状态码
int responseCode = connection.getResponseCode();
if (responseCode == -1) {
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
//如果没有响应body
if (!hasResponseBody(request.getMethod(), responseCode)) {
return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields()));
}
//如果有响应body
return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields()),
connection.getContentLength(), inputStreamFromConnection(connection));
}
/**
* Opens an {@link HttpURLConnection} with parameters.
* @param url
* @return an open connection
* @throws IOException
*/
private HttpURLConnection openConnection(URL url, Request request) throws IOException {
HttpURLConnection connection = createConnection(url);
int timeoutMs = request.getTimeoutMs();
connection.setConnectTimeout(timeoutMs);
connection.setReadTimeout(timeoutMs);
connection.setUseCaches(false);
connection.setDoInput(true);
// use caller-provided custom SslSocketFactory, if any, for HTTPS
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
}
return connection;
}
/**
* Create an {@link HttpURLConnection} for the specified {@code url}.
*/
protected HttpURLConnection createConnection(URL url) throws IOException {
//每次调用此 URL 的协议处理程序的 openConnection 方法都打开一个新的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Workaround for the M release HttpURLConnection not observing the
// HttpURLConnection.setFollowRedirects() property.
// https://code.google.com/p/android/issues/detail?id=194495
connection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects());
return connection;
}
这样就将HttpResponse 返回到了BasicNetwork。