Volley源码解析
来源:互联网 发布:不用手机注册淘宝账号 编辑:程序博客网 时间:2024/06/06 12:44
从newRequestQueue进行入手来进行一步步分析源码的流程
public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, null); } public static RequestQueue newRequestQueue(Context context, HttpStack stack){ return newRequestQueue(context, stack, -1);}
我们可以查看出来,它进行重载了两个方法来进行使用,最后的方法是下面这个
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { //参数一:缓存到手机内置内存中 //参数二:通过查看我们可以发现,这个文件夹的名字是volley File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); 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) { //HttpUrlConnection中的stack stack = new HurlStack(); } else { //HttpClient中的HttpClientStack stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start(); return queue; }
通过上面的代码我们可以看出来,它会判断当前的sdk的大小,如果当前的sdk>=9,它会调用HurlStack(),否则,它会调用HttpClientStack这个方法
1.HurlStack 与 HttpClientStack 区别
由此可见,在Android 2.2 中HttpClient拥有较少的bug,所以使用它比较合适,在Android 2.3以后HttpUrlConnection是最佳的选择。它的api简单,体积比较小,因此非常试用于Android项目。压缩和缓存机制可以有效的减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。
HurlStack中的父类的源码进行分析
/** * An HTTP stack abstraction. * 抽象的http栈 */ public interface HttpStack { /** * Performs an HTTP request with the given parameters. * 根据参数,执行http请求 * <p>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().</p> * * @param request the request to perform * @param additionalHeaders additional headers to be sent together with * {@link Request#getHeaders()} * @return the HTTP response */ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }
该父类主要规定了,子类必须有一个根据request请求数据,并且返回HttpResponse类的方法
OK,接下来我们先看HurlStack,这个类使用的是HttpURLConnection作为连接方式,在sdk较高版本推荐使用(其实目前市场上2.3的系统已经很少见了)
我们直接看这个类的核心方法performRequest()
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<String, String>(); 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 parsedUrl = new URL(url); 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. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);//http协议 int responseCode = connection.getResponseCode();//获取响应状态 if (responseCode == -1) {//-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."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage());//响应状态类 BasicHttpResponse response = new BasicHttpResponse(responseStatus); response.setEntity(entityFromConnection(connection));//解析响应实体 for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头 if (header.getKey() != null) { Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); } } return response; }
整个方法分成几个步骤,首先是将请求参数,存储到map当中
HashMap<String, String> map = new HashMap<String, String>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders);
然后是开启url连接
URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接
来看openConnection()方法
/** * 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) {//https ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory); } return connection; } /** * Create an {@link HttpURLConnection} for the specified {@code url}. */ protected HttpURLConnection createConnection(URL url) throws IOException { return (HttpURLConnection) url.openConnection(); }
这个方法主要就是调用url.openConnevtion()从而返回一个HttpURLConnection对象,其中的一些超时设置,是由request本身提供的
另外还根据url是否带有https,为HttpURLConnection设置setSSLSocketFactory(mSslSocketFactory对象是在构造方法中传入的)
得到HttpURLConnection,就设置请求参数
for (String headerName : map.keySet()) {//添加请求参数 connection.addRequestProperty(headerName, map.get(headerName)); }
然后是确定请求方式(GET,POST还是别的)
setConnectionParametersForRequest(connection, request);//设置请求方式
setConnectionParametersForRequest方法:
@SuppressWarnings("deprecation") /** * 设置请求方式 * @param connection * @param request * @throws IOException * @throws AuthFailureError */ /* package */ static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: // This is the deprecated way that needs to be handled for backwards compatibility. // If the request's post body is null, then the assumption is that the request is // GET. Otherwise, it is assumed that the request is a POST. byte[] postBody = request.getPostBody(); if (postBody != null) { // Prepare output. There is no need to set Content-Length explicitly, // since this is handled by HttpURLConnection using the size of the prepared // output stream. connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(postBody); out.close(); } break; case Method.GET: // Not necessary to set the request method because connection defaults to GET but // being explicit here. connection.setRequestMethod("GET"); break; case Method.DELETE: connection.setRequestMethod("DELETE"); break; case Method.POST: connection.setRequestMethod("POST"); addBodyIfExists(connection, request); break; case Method.PUT: connection.setRequestMethod("PUT"); addBodyIfExists(connection, request); break; case Method.HEAD: connection.setRequestMethod("HEAD"); break; case Method.OPTIONS: connection.setRequestMethod("OPTIONS"); break; case Method.TRACE: connection.setRequestMethod("TRACE"); break; case Method.PATCH: connection.setRequestMethod("PATCH"); addBodyIfExists(connection, request); break; default: throw new IllegalStateException("Unknown method type."); } }
最后获取响应,将响应头信息包装成StatusLine对象,再包装成BasicHttpResponse对象
StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage());//响应状态类 BasicHttpResponse response = new BasicHttpResponse(responseStatus);
然后为BasicHttpResponse加入响应内容
response.setEntity(entityFromConnection(connection));//解析响应实体
entityFromConnection(HttpURLConnection connection)方法:
/** * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}. * <br>解析出响应实体 * @param connection * @return an HttpEntity populated with data from <code>connection</code>. */ private static HttpEntity entityFromConnection(HttpURLConnection connection) { BasicHttpEntity entity = new BasicHttpEntity(); InputStream inputStream; try { inputStream = connection.getInputStream(); } catch (IOException ioe) { inputStream = connection.getErrorStream(); } entity.setContent(inputStream); entity.setContentLength(connection.getContentLength()); entity.setContentEncoding(connection.getContentEncoding()); entity.setContentType(connection.getContentType()); return entity; }
最后,加入响应头部内容
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头 if (header.getKey() != null) { Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); } }
OK,这样就返回了一个具有完整信息的HttpResponse对象。整个过程比较简单,是常规的网络请求内容。
2.HttpClientStack的实现,直接来看performRequest()方法
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); addHeaders(httpRequest, additionalHeaders);//添加缓存头 addHeaders(httpRequest, request.getHeaders());//添加请求头 onPrepareRequest(httpRequest);//请求预处理 HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // TODO: Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); return mClient.execute(httpRequest); }
请求步骤,首先是根据请求方式,构造HttpUriRequest对象,并且设置请求参数
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
createHttpRequest()方法:
/** * Creates the appropriate subclass of HttpUriRequest for passed in request. * 根据请求方式返回对应HttpUriRequest的子类 */ @SuppressWarnings("deprecation") /* protected */ static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: { // This is the deprecated way that needs to be handled for backwards compatibility. // If the request's post body is null, then the assumption is that the request is // GET. Otherwise, it is assumed that the request is a POST. byte[] postBody = request.getPostBody(); if (postBody != null) { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); HttpEntity entity; entity = new ByteArrayEntity(postBody); postRequest.setEntity(entity); return postRequest; } else { return new HttpGet(request.getUrl()); } } case Method.GET: return new HttpGet(request.getUrl()); case Method.DELETE: return new HttpDelete(request.getUrl()); case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request);//设置请求参数 return postRequest; } case Method.PUT: { HttpPut putRequest = new HttpPut(request.getUrl()); putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(putRequest, request); return putRequest; } case Method.HEAD: return new HttpHead(request.getUrl()); case Method.OPTIONS: return new HttpOptions(request.getUrl()); case Method.TRACE: return new HttpTrace(request.getUrl()); case Method.PATCH: { HttpPatch patchRequest = new HttpPatch(request.getUrl()); patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(patchRequest, request); return patchRequest; } default: throw new IllegalStateException("Unknown request method."); } }
从createHttpRequest()方法可以看出,在HttpClient中,只要根据请求方式,new一个HttpGet/HttpPost/….对象就可以了(而urlstack这一步是真的connnection而言的)
接着是为HttpUriRequest对象设置请求头部
addHeaders(httpRequest, additionalHeaders);//添加缓存头 addHeaders(httpRequest, request.getHeaders());//添加请求头
addHeaders方法:
/** * 添加响应头 * @param httpRequest * @param headers */ private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { for (String key : headers.keySet()) { httpRequest.setHeader(key, headers.get(key)); } }
最后,将HttpUriRequest对象交给httpClient执行
return mClient.execute(httpRequest);
3.HurlStack与HttpClientStack区别进行总结
OK,HttpClientStack比我们想象的还要简单,起码比HurlStack简单,这是当然的,因为使用httpClient方式,其本质就是对urlConnection的封装,然而这个封装并不是很完美,所以造成了版本之间的差异。
2. new RequestQueue(new DiskBasedCache(cacheDir), network)这里面的源码进行分析
我们点击跳转到这个构造方法中
//参数一:缓存 参数二:联网工作的状态public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);}当点击里面的那个this方法时候会跳转到如下构造函数中 public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));}
通过分析我们可以发现,最后是将网络请求响应的数据发送到主线程进行操作的
3.queue.start(); 这个里面的方法中进行分析
public void start() { //确保当前正在运行的调度程序已经停止 stop(); //参数一:实例化缓存分流队列 //参数二:实际化到达网络的请求队列 //参数三:用于检索和存储响应的高速缓存接口 //参数四:响应传递机制 mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { //参数一:实际化到达网络的请求队列 //参数二:用于检索和存储响应的高速缓存接口 //参数三:参数四:响应传递机制 NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
CacheDispatcher是缓存调度线程,在调用start()方法。在循环中调用了NetworkDispatcher网络调度线程。默认情况下网络调度线程是4,缓存调度线程是一个,一共5个线程在后台运行并等待请求的到来。同时进行添加到请求到队列里面来。
接下来我们一起来看一下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; } // Insert request into stage if there's already a request with the same cache key in flight. synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); //如果此前有相同的请求且还没有返回结果,就将次请求加入mWaitingRequests队列 if (mWaitingRequests.containsKey(cacheKey)) { // 如果有已经在队列的请求,后面的进行等待 Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { stagedRequests = new LinkedList<Request<?>>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); if (VolleyLog.DEBUG) { VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); } } else { // Insert 'null' queue for this cacheKey, indicating there is now a request in // flight. mWaitingRequests.put(cacheKey, null); mCacheQueue.add(request); } return request; } }
代码分析:request.shouldCache()判断是否可以进行缓存的,默认是可以缓存的。如果不能缓存,则将请求添加到网络请求队列里面。如果能缓存,则判断之前是否有执行相同的请求且没有返回结果的,如果有的话将此请求加入到mWaitingRequests队列中,不再进行重复的请求,没有的话就请求加入到缓存的队列mCacheQueue.RequestQueue的add方法并没有请求网络或者对缓存的操作,当将请求添加到网络请求的队列或者缓存队列时,在后台的网络调度线程和缓存调度线程轮询各自的请求队列,若发现有请求任务则开始执行。
我们来看一下缓存调度线程CacheDispatcher
@Overridepublic void run() { if (DEBUG) VolleyLog.v("start new dispatcher"); //线程优先级设置为最高级别 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Make a blocking call to initialize the cache. mCache.initialize(); Request<?> request; while (true) { // release previous request object to avoid leaking request object when mQueue is drained. request = null; try { // 获取缓存队列中的一个请求 request = mCacheQueue.take(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } try { 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"); // Cache miss; send off to the network dispatcher. mNetworkQueue.put(request); continue; } // 判断缓存的响应是否过期 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // We have a cache hit; parse its data for delivery back to the request. request.addMarker("cache-hit"); //对数据的解析并回调给主线程 Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. mDelivery.postResponse(request, response); } else { // Soft-expired cache hit. We can deliver the cached response, // but we need to also send the request to the network for // refreshing. request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // Mark the response as intermediate. response.intermediate = true; // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. final Request<?> finalRequest = request; mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(finalRequest); } catch (InterruptedException e) { // Not much we can do about this. } } }); } } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); } }}
分析:首先从缓存队列取出请求,判断请求是否取消,如果请求没有被取消则判断是否有缓存的响应,如果有缓存的响应。如果有缓存的响应并且没有过期,则对缓存响应进行解析并回调给主线程:如果没有缓存的响应,则将请求添加到网络调度线程
网络调度线程NetworkDispatcher
@Overridepublic void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Request<?> request; while (true) { long startTimeMs = SystemClock.elapsedRealtime(); // release previous request object to avoid leaking request object when mQueue is drained. request = null; try { // 从队列中取出请求 request = mQueue.take(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } try { request.addMarker("network-queue-take"); // If the request was cancelled already, do not perform the // network request. if (request.isCanceled()) { request.finish("network-discard-cancelled"); continue; } addTrafficStatsTag(request); // Perform the network request. NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // If the server returned 304 AND we delivered a response already, // we're done -- don't deliver a second identical response. if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } // Parse the response here on the worker thread. Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); // Write to cache if applicable. // TODO: Only update cache metadata instead of entire record for 304s. if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // Post the response back. 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); } }}
这个网络调度线程和缓存调度线程处理的逻辑几乎相同,在这里,不做过多的介绍了,mNetwork.performRequest(request);我们可以观察到这个里面是个接口,实现类是BasicNetwork,我们来接着往下进行分析
1.Network接口类代码如下
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 */ public NetworkResponse performRequest(Request<?> request) throws VolleyError;}
2.BasicNetwork中的performRequest里面的请求进行分析
/** * @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); } } }}
代码解析:
1.先是通过mHttpStack把请求执行并且获取它的响应结果,根据HttpStatus做出各种判断。2.然后再把httpResponse的Entity转化为ByteArray,并处理各种发生的异常。3.最后的过程是这样的:通过Volley创建一个RequestQueue请求队列,当这个队列开始运作的时候会启动NetworkDispatcher这个工作线程,而BasicNetwork的performRequest()的方法就在NetworkDispatcher线程run()方法中调用,然后通过mHttpStack的performRequest()方法获取一个networkResponse,在NetworkDispatcher线程把这个networkResponse转化为期望的数据类型,比如Response<String>,Response<Json>,Response<Bitmap>。
3. mDelivery.postResponse(request, response);
@Overridepublic void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));}
4.ResponseDeliveryRunnable我们来看一下这里面都做了什么处理的
/** * 在主线程进行返回一个网络响应的交付线程 */@SuppressWarnings("rawtypes")private 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(); } }}
Volley源码分析结束。
- 【Volley】Volley源码解析
- volley源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- 如何保证Service不被杀死一直运行
- Netty
- 移动端头部代码解释
- uva 11997 K Smallest Sums
- 数据结构-迷宫问题(回溯法)
- Volley源码解析
- 如何在VS2010中连接MySQL和Access数据库
- struts2中struts.xml按照一定顺序排列
- (三十八)CoordinatorLayout 源码分析及手写 CoordinatorLayout 以及 NestedScrolling 机制
- 【操作系统】页式储存方式,页,页表,页表项
- selenium在指定元素上方进行鼠标悬浮
- Java反射机制(源码反射优势解析)
- 数据结构实验之查找五:平方之哈希表
- BeanUtils.copyProperties使用