网络请求中有几个转换解析请求获取响应结果的地方:
1.HttpStack接口的performRequest()方法
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
2.Network接口的performRequest()方法
public NetworkResponse performRequest(Request<?> request)
3.Request类的parseNetworkResponse()抽象方法
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
可以很鲜明得看出第一个是对原生Http请求的解析,解析出来是一个Apach的HttpResponse 实例,这个结果就是通过上述两个HttpStack的实现类HttpClientStack和HurlStack执行获取的获取的。
而第二个解析出来是框架自定的NetworkResponse,这是通过Network的实现类BasicNetwork来获取的。
第三个就是第二个得出来NetworkResponse解析成用户期望Response<T> 了,这个Response和Request是对应的,有String型,json型还有Image型的。然后在通过ResponseDelivery把解析好的结果发送到主线程。
从Request到Response就是这样一步步走来的。
/** * @title performRequest执行各种Request请求并以NetworkResponse的形式返回结果 * @param Request * @return NetworkResponse * @throws VolleyError * 定义:{@link Network#performRequest(Request)} * 被调:{@link NetworkDispatcher#run()} * */ @Override//NetworkDispatcher的run()方法中调用 public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime();//开始请求时间 while (true) { HttpResponse httpResponse = null;//apache的请求结果 byte[] responseContents = null;//请求的内容 Map<String, String> responseHeaders = new HashMap<String, String>();//响应结果头部信息 try { // Gather headers. Map<String, String> headers = new HashMap<String, String>();//保存缓存数据 addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据 httpResponse = mHttpStack.performRequest(request, headers);//去调用mHttpStack的实现方法执行请求 StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线 int statusCode = statusLine.getStatusCode();//获取状态码 responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation.//处理缓存验证 if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据 return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } //把HttpEntity转化为byte[]数据 responseContents = entityToBytes(httpResponse.getEntity()); // if the request is slow, log it.//如果请求很慢,就打印出来看一下 long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine);//打印 //连接正常但是返回无内容,抛出IO异常 if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) { throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false); } catch (SocketTimeoutException e) {//读取超时,重试 attemptRetryOnException("socket", request, new TimeoutError()); } catch (ConnectTimeoutException e) {//连接超时,重试 attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) {//Bad URL throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) {//IO异常 int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else {//如果没有返回httpResponse,就说明没连接 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);//创建响应体 if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {//认证失败异常,重试 attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else {//服务器异常 // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse);//只有状态码为5XX才抛出服务器异常 } } else {//网络异常 throw new NetworkError(networkResponse); } } } }
A:先是通过mHttpStack把请求执行并且获取它的响应结果,根据HttpStatus做出各种判断。
B:然后再把httpResponse的Entity转化为ByteArray,并处理各种发生的异常。
C:最后的过程是这样的:通过Volley创建一个RequestQueue请求队列,当这个队列开始运作的时候会启动NetworkDispatcher这个工作线程,而BasicNetwork的performRequest()的方法就在NetworkDispatcher线程run()方法中调用,然后通过mHttpStack的performRequest()方法获取一个networkResponse,在NetworkDispatcher线程把这个networkResponse转化为期望的数据类型,比如Response<String>,Response<Json>,Response<Bitmap>。
public class NetworkImageView extends ImageView { /** The URL of the network image to load */ private String mUrl; /** * Resource ID of the image to be used as a placeholder until the network image is loaded. */ private int mDefaultImageId;//无本地图片时显示的空图 /** * Resource ID of the image to be used if the network response fails. */ private int mErrorImageId; /** Local copy of the ImageLoader. */ private ImageLoader mImageLoader; /** Current ImageContainer. (either in-flight or finished) */ private ImageContainer mImageContainer; ...... /** * Loads the image for the view if it isn't already loaded. * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise. */ private void loadImageIfNecessary(final boolean isInLayoutPass) { int width = getWidth(); int height = getHeight(); ...... // The pre-existing content of this view didn't match the current URL. Load the new image // from the network. ImageContainer newContainer = mImageLoader.get(mUrl, new ImageListener() { @Override public void onErrorResponse(VolleyError error) { if (mErrorImageId != 0) { setImageResource(mErrorImageId); } } @Override public void onResponse(final ImageContainer response, boolean isImmediate) { // If this was an immediate response that was delivered inside of a layout // pass do not set the image immediately as it will trigger a requestLayout // inside of a layout. Instead, defer setting the image by posting back to // the main thread. if (isImmediate && isInLayoutPass) { post(new Runnable() { @Override public void run() { onResponse(response, false); } }); return; } if (response.getBitmap() != null) { setImageBitmap(response.getBitmap()); } else if (mDefaultImageId != 0) { setImageResource(mDefaultImageId); } } }); // update the ImageContainer to be the new bitmap container. mImageContainer = newContainer; } ...... }
public class ImageLoader { /** RequestQueue for dispatching ImageRequests onto. */ private final RequestQueue mRequestQueue; /** Amount of time to wait after first response arrives before delivering all responses. */ private int mBatchResponseDelayMs = 100; /** The cache implementation to be used as an L1 cache before calling into volley. */ private final ImageCache mCache; /** * HashMap of Cache keys -> BatchedImageRequest used to track in-flight requests so * that we can coalesce multiple requests to the same URL into a single network request. */ private final HashMap<String, BatchedImageRequest> mInFlightRequests = new HashMap<String, BatchedImageRequest>(); /** HashMap of the currently pending responses (waiting to be delivered). */ //BatchedImageRequest用于匹配一个Request和一组对该Request的返回结果感兴趣的ImageContainer,这样可以把相同的Request合并 private final HashMap<String, BatchedImageRequest> mBatchedResponses = new HashMap<String, BatchedImageRequest>(); /** Handler to the main thread. */ private final Handler mHandler = new Handler(Looper.getMainLooper()); /** Runnable for in-flight response delivery. */ private Runnable mRunnable; ...... /** * Issues a bitmap request with the given URL if that image is not available * in the cache, and returns a bitmap container that contains all of the data * relating to the request (as well as the default image if the requested * image is not available). * @param requestUrl The url of the remote image * @param imageListener The listener to call when the remote image is loaded * @param maxWidth The maximum width of the returned image. * @param maxHeight The maximum height of the returned image. * @return A container object that contains all of the properties of the request, as well as * the currently available image (default if remote is not loaded). */ public ImageContainer get(String requestUrl, ImageListener imageListener, int maxWidth, int maxHeight) { // only fulfill requests that were initiated from the main thread. throwIfNotOnMainThread();//必须在主线程创建requests final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight); // Try to look up the request in the cache of remote images. Bitmap cachedBitmap = mCache.getBitmap(cacheKey);//先查找缓存是否命中 if (cachedBitmap != null) {//缓存命中 // Return the cached bitmap. ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); imageListener.onResponse(container, true); return container; } // The bitmap did not exist in the cache, fetch it! ImageContainer imageContainer = new ImageContainer(null, requestUrl, cacheKey, imageListener);//ImageContainer是一个数据类 // Update the caller to let them know that they should use the default bitmap. imageListener.onResponse(imageContainer, true); // Check to see if a request is already in-flight. BatchedImageRequest request = mInFlightRequests.get(cacheKey); if (request != null) { // If it is, add this request to the list of listeners. request.addContainer(imageContainer); return imageContainer; } // The request is not already in flight. Send the new request to the network and // track it. Request<?> newRequest = new ImageRequest(requestUrl, new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { onGetImageSuccess(cacheKey, response); } }, maxWidth, maxHeight, Config.RGB_565, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { onGetImageError(cacheKey, error); } });//ImageRequest具有将原始网络请求编码成Bitmap的功能 mRequestQueue.add(newRequest);//向mRequestQueue增加ImageRequest,注意各个线程都只和同步队列打交道,各个线程因此解耦 mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer)); return imageContainer; } ...... }
原文:http://blog.csdn.net/mba16c35/article/details/44589137