volley源码解析
来源:互联网 发布:qt高级编程 源代码 编辑:程序博客网 时间:2024/04/19 13:02
假设你已经学会volley的基本应用,如果不熟悉请看官网介绍及其例子。
下面开始volley源码解析,有什么错的地方希望大家指出。
首先,从入口开始解析源码:
public class Volley { /** Default on-disk cache directory. */ private static final String DEFAULT_CACHE_DIR = "volley"; /** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @param stack An {@link HttpStack} to use for the network, or null for default. * @return A started {@link RequestQueue} instance. */ public static RequestQueue newRequestQueue(Context context, HttpStack stack) { Log.i("Volley-deepdig", "Volley newRequestQueue(Context context, HttpStack stack)"); 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) { stack = new HurlStack(); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; } /** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @return A started {@link RequestQueue} instance. */ public static RequestQueue newRequestQueue(Context context) { Log.i("Volley-deepdig", "Volley newRequestQueue(Context context)"); return newRequestQueue(context, null); }}
首先我们传个context来调用一个参数的构造方法,接着调用2个参数的构造方法。
在这里volley做了2件事,实例化2个参数:
1)根据api版本决定发出请求的是Httpclient还是HttpUrlConnection,api9之前的版本用的是前者,反之是后者(注释上写在2.3之前HttpUrlConnrcttion不可靠,有兴趣的可以前往 注释的链接去看看)。接着把new出来的实例作为参数传入BasicNetwork中使其实例化。
2)根据路径实例化DiskBasedCache,并将DiskBasedCache和BasicNetwork作为参数传入RequestQueue使其实例化,并调用start方法。
我们接着看看RequestQueue中的源码
/** The cache triage queue. */ private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>(); /** The queue of requests that are actually going out to the network. */ private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; } /** * Creates the worker pool. Processing will not begin until {@link #start()} is called. * * @param cache A Cache to use for persisting responses to disk * @param network A Network interface for performing HTTP requests * @param threadPoolSize Number of network dispatcher threads to create */ public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } /** * Creates the worker pool. Processing will not begin until {@link #start()} is called. * * @param cache A Cache to use for persisting responses to disk * @param network A Network interface for performing HTTP requests */ public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); } /** * Starts the dispatchers in this queue. */ public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. 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(); } }
下面是需要注意的几点:
1.用阻塞队列PriorityBlockingQueue来支持并发操作,用来装add进来的request,mCacheQueue是需要缓存resquest的队列,而mNetworkQueue的request则是不需要缓存的。
2.27行代码, ExecutorDelivery为后面埋下伏笔,是用来将请求完的得到结果回调到主线程上。
3.start方法中,开启了1个 CacheDispatcher缓存调度线程,以后所有需要缓存的请求将在此线程拦截,并将先前已请求过的存下来的response缓存直接返回。
开启了4个NetworkDispatcher调度线程来处理添加进请求队列的request。注意:CacheDispatcher中是将2个阻塞队列都传进去了,需要缓存不需要缓存的都进去了
接下来我们看NetworkDispatcher的源码
@Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); while (true) { long startTimeMs = SystemClock.elapsedRealtime(); Request<?> request; try { // Take a request from the queue. 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); } } }
NetworkDispatcher和CaceDispatcher都继承成Thread,核心都在run方法上。
在run方法死循环中:
1.第9行代码不断把reqeust从请求队列中拿出来。PriorityBlockingQueue的take方法会把元素拿出来并移除,并且是Lock同步的,要知道一共有好几个调度线程在同时对队列进行操作,这个是我们需要知道的。
2.第31行代码,最开始初始化的BasicNetwork终于派上用场了,调用performRequest()方法;
源码跟踪过去
@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 { // Gather headers. Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); httpResponse = mHttpStack.performRequest(request, headers); StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation. if (statusCode == HttpStatus.SC_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // A HTTP 304 response does not have all header fields. We // have to use the header fields from the cache entry plus // the new ones from the response. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) { responseContents = entityToBytes(httpResponse.getEntity()); } 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, statusLine); 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 (ConnectTimeoutException e) { attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().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); 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); } } else { throw new NetworkError(networkResponse); } } } }
第12行代码,传入request和headers(此headers不是http的headers)调用HurlStack的performRequest(Request<?> request, Map<String, String> additionalHeaders)方法。
继续跟踪HurlStack的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); 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."); } 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; }
此方法根据传过来的request的url,header,method(Post,Get,Deltele,Put...),用HttpUrlConnection发出请求,并返回HttpResponse(真正意义上http协议返回的Response)。
HurlStack的工作已经完毕,目的只是返回一个HttpResponse。我们接着看BasckNetWork的performRequest(Request<?> request)方法,拿到HttpResponse后这个方法根据response组装一个NetworkResponse(这个NetworkResponse是Volley自定义的数据集)并返回。
回到NetworkDispatcher,我们发现第31行代码已经执行完毕了,并返回了了一个 NetworkResponse。再看看第32行代码 request.addMarker("network-http-complete"),请求已经标记完成。
接着看第42行代码,Response<?> response = request.parseNetworkResponse(networkResponse);
又要跟过去了,且看看Request源码,下面只截了相关的2个方法
abstract protected Response<T> parseNetworkResponse(NetworkResponse response); abstract protected void deliverResponse(T response);
发现是抽象方法,我们只好拿Request的其中一个子类StringRequest开刀了,且看
/** * A canned request for retrieving the response body at a given URL as a String. */public class StringRequest extends Request<String> { private final Listener<String> mListener; /** * Creates a new request with the given method. * * @param method the request {@link Method} to use * @param url URL to fetch the string at * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } /** * Creates a new GET request. * * @param url URL to fetch the string at * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(String response) { mListener.onResponse(response); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); }}
如果我们add到RequestQueue的是StringRequest,将会按照其实现的返回Response,Response和HttpHeaderParser中调用的方法请自行查看,难度不大。接着NetworkDispatcher的第44行代码已经标记network解析完成了,第43行也返回了一个Response(Volley层面上的Response)。
快接近真相了,兄弟再忍着头皮看下去吧,其实我也累爆了....
让我们接着看NetworkDispatcher的第56行代码 mDelivery.postResponse(request, response),这个mDelivery正是前面RequestQueue源码的第27行,伏笔阿。
让我们看看ExecutorDelivery的源码
/** * Delivers responses and errors. */public class ExecutorDelivery implements ResponseDelivery { /** Used for posting responses, typically to the main thread. */ private final Executor mResponsePoster; /** * Creates a new response delivery interface. * @param handler {@link Handler} to post responses on */ public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. mResponsePoster = new Executor() { @Override public void execute(Runnable command) { handler.post(command); } }; } /** * Creates a new response delivery interface, mockable version * for testing. * @param executor For running delivery tasks */ public ExecutorDelivery(Executor executor) { mResponsePoster = executor; } @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"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); } @Override public void postError(Request<?> request, VolleyError error) { request.addMarker("post-error"); Response<?> response = Response.error(error); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null)); } /** * A Runnable used for delivering network responses to a listener on the * main thread. */ @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 this request has canceled, finish it and don't deliver. if (mRequest.isCanceled()) { mRequest.finish("canceled-at-delivery"); return; } // Deliver a normal response or error, depending. if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); } // If this is an intermediate response, add a marker, otherwise we're done // and the request can be finished. if (mResponse.intermediate) { mRequest.addMarker("intermediate-response"); } else { mRequest.finish("done"); } // If we have been provided a post-delivery runnable, run it. if (mRunnable != null) { mRunnable.run(); } } }}
看看带Handler参数的构造方法,正是RequestQueue源码中实例化的。用一个Executor调度器,不断将线程切到主线程上。
接着看第40行代码,Executor调度器执行任务ResponseDeliveryRunnable,并把request和response传过去了,还传了个空的Runable对象。
继续看ResponseDeliveryRunnable的run方法,第76行和第77行,如果response标记成功,则request将response的result(范型,如果是StringRequest则是String,JsonRequest则是Json)对象回调。回调到哪呢?
且回看上面StringRequest的源码第34行,mListener.onResponse(response),而mListener正是Response源码中的接口,还是看看吧...
public class Response<T> { /** Callback interface for delivering parsed responses. */ public interface Listener<T> { /** Called when a response is received. */ public void onResponse(T response); } /** Callback interface for delivering error responses. */ public interface ErrorListener { /** * Callback method that an error has been occurred with the * provided error code and optional user-readable message. */ public void onErrorResponse(VolleyError error); } /** Returns a successful response containing the parsed result. */ public static <T> Response<T> success(T result, Cache.Entry cacheEntry) { return new Response<T>(result, cacheEntry); } /** * Returns a failed response containing the given error code and an optional * localized message displayed to the user. */ public static <T> Response<T> error(VolleyError error) { return new Response<T>(error); } /** Parsed response, or null in the case of error. */ public final T result; /** Cache metadata for this response, or null in the case of error. */ public final Cache.Entry cacheEntry; /** Detailed error information if <code>errorCode != OK</code>. */ public final VolleyError error; /** True if this response was a soft-expired one and a second one MAY be coming. */ public boolean intermediate = false; /** * Returns whether this response is considered successful. */ public boolean isSuccess() { return error == null; } private Response(T result, Cache.Entry cacheEntry) { this.result = result; this.cacheEntry = cacheEntry; this.error = null; } private Response(VolleyError error) { this.result = null; this.cacheEntry = null; this.error = error; }}
我们new StringRequest的时候要求传入的正是Listener,而且必须实现其方法,而StringRequest的第34行则进行了回调。如果你还不知道回调哪,且看下面...
StringRequest request = new StringRequest(Request.Method.GET,"http://.....", new Response.Listener<String>() {@Overridepublic void onResponse(String result) {//哥们,回调在此}}, new ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {}});
在此,流程就算走完了。还有一个CacheDispatcher 就留着各位兄弟自己看吧,只是把缓存丢失和过期的request添加到不用缓存的请求队列中,而NetWorkDispatcher则不断
从不用缓存的请求队列拿request请求。
如果兄弟看的还是很迷糊,最后来个总结吧。
从Volley中实例化RequestQueue,并执行start方法,实例化并执行1个CacheDispatcher 有缓存的请求调度器和4个NetWorkDispatcher不需要缓存的请求调度器。我们一往RequestQueue添加request(StringRequest,JsonObjectRequest....),调度器就在不断执行,别忘了CacheDispatcher和NetWorkDispatcher有死循环不断在执行。
下次有空将会讲解Volley的缓存,提示(其实CacheDispatcher和NetWorkDispatcher有点像生产者-消费者模式,因为Volley的缓存失效是由服务器的header实现,有点坑)
- 【Volley】Volley源码解析
- volley源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- 使用svn diff的-r参数的来比较任意两个版本的差异
- Android Sensor系统剖析(2.3.5)(上)
- cocos2d-x游戏开发 回调函数
- 浅析C++多线程内存模型
- js数组的操作
- volley源码解析
- Vim7.4的命令之多标签编辑
- web1800远程服务的开放融合之道
- Linux下HugePage内存功能配置
- hi3518e移植USB-WiFi RT3070 STA驱动
- java 反射
- 26. Remove Duplicates from Sorted Array Leetcode Python
- 希尔排序
- python实现查看linux网络流量的小程序: netiostat