Volley 源码解读
大家都知道谷歌现在已经不维护volley框架,为什么现在还要分析volley源码呢。
首先,volley框架的设计思想是非常值得借鉴,翻下当下个人开源 的一些网络框架,很多都是借鉴的volley的设计思想完成的。
另外,volley 源码相对简单易懂。
一、首先volley使用不同请求模式需要new一个相应的request对象
以stringrequest为例:
1 public void testVolley() { 2 RequestQueue requestQueue = Volley.newRequestQueue(this);//创建一个队列 3 StringRequest stringRequest = new StringRequest("", new Response.Listener<String>() { 4 @Override 5 public void onResponse(String response) { 6 7 } 8 }, new Response.ErrorListener() { 9 @Override 10 public void onErrorResponse(VolleyError error) { 11 12 } 13 }); 14 requestQueue.add(stringRequest);//把1请求添加进队列 15 16 }
同理需要json串的请求,则new出一个JsonRequest 图片则new出 ImageRequest 这是标准的策略模式。方便扩展,比如我们后期需要请求自定义的数据格式,就可以继承request这个类,比照stringrequest写出自己的request来完成网络数据的获取和解析。
具体使用代码就不写了。
二、源码分析
1 public static RequestQueue newRequestQueue(Context context, HttpStack stack) { 2 File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); 3 4 String userAgent = "volley/0"; 5 try { 6 String packageName = context.getPackageName(); 7 PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); 8 userAgent = packageName + "/" + info.versionCode; 9 } catch (NameNotFoundException e) { 10 } 11 12 if (stack == null) { 13 if (Build.VERSION.SDK_INT >= 9) { 14 stack = new HurlStack(); 15 } else { 16 // Prior to Gingerbread, HttpUrlConnection was unreliable. 17 // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html 18 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); 19 } 20 } 21 22 Network network = new BasicNetwork(stack); 23 24 RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); 25 queue.start(); 26 27 return queue; 28 }
1、创建一个请求队列会调用Volley类中的 newRequestQueue方法。我们主要看第24、25行(标红)创建后调用了 queue的start方法
1 public void start() { 2 stop(); // Make sure any currently running dispatchers are stopped. 3 // Create the cache dispatcher and start it. 4 mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); 5 mCacheDispatcher.start(); 6 7 // Create network dispatchers (and corresponding threads) up to the pool size. 8 for (int i = 0; i < mDispatchers.length; i++) { 9 NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, 10 mCache, mDelivery); 11 mDispatchers[i] = networkDispatcher; 12 networkDispatcher.start(); 13 } 14 }
2、创建一个缓存线程4、5行和四个网络请求线程8--12行。(mDispatchers.length默认值为4)并 调用他们的start()方法
CacheDispatcher和NetworkDispatcher都是继承于 Thead类的。start的方法就是启动该线程
3、大家都熟悉thread的用法,调用start后肯定是执行run方法我们接下来看看NetworkDispatcher的run方法做了什么
1 @Override 2 public void run() { 3 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 4 while (true) { 5 long startTimeMs = SystemClock.elapsedRealtime(); 6 Request<?> request; 7 try { 8 // Take a request from the queue. 9 request = mQueue.take(); 10 } catch (InterruptedException e) { 11 // We may have been interrupted because it was time to quit. 12 if (mQuit) { 13 return; 14 } 15 continue; 16 } 17 18 try { 19 request.addMarker("network-queue-take"); 20 21 // If the request was cancelled already, do not perform the 22 // network request. 23 if (request.isCanceled()) { 24 request.finish("network-discard-cancelled"); 25 continue; 26 } 27 28 addTrafficStatsTag(request); 29 30 // Perform the network request. 31 NetworkResponse networkResponse = mNetwork.performRequest(request); 32 request.addMarker("network-http-complete"); 33 34 // If the server returned 304 AND we delivered a response already, 35 // we're done -- don't deliver a second identical response. 36 if (networkResponse.notModified && request.hasHadResponseDelivered()) { 37 request.finish("not-modified"); 38 continue; 39 } 40 41 // Parse the response here on the worker thread. 42 Response<?> response = request.parseNetworkResponse(networkResponse); 43 request.addMarker("network-parse-complete"); 44 45 // Write to cache if applicable. 46 // TODO: Only update cache metadata instead of entire record for 304s. 47 if (request.shouldCache() && response.cacheEntry != null) { 48 mCache.put(request.getCacheKey(), response.cacheEntry); 49 request.addMarker("network-cache-written"); 50 } 51 52 // Post the response back. 53 request.markDelivered(); 54 mDelivery.postResponse(request, response); 55 } catch (VolleyError volleyError) { 56 volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); 57 parseAndDeliverNetworkError(request, volleyError); 58 } catch (Exception e) { 59 VolleyLog.e(e, "Unhandled exception %s", e.toString()); 60 VolleyError volleyError = new VolleyError(e); 61 volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); 62 mDelivery.postError(request, volleyError); 63 } 64 } 65 }
第四行是一个while(true)循环。说明该方法是一直在执行。主要逻辑是从requestQueue中不断取出网络任务去执行。二queue中的任务就是在我们使用volley时的最后一行代码 requestQueue.add(stringRequest);//把1请求添加进队列
看到此处大家就需要明白,为什么volley官方明确要求 我们所有的网络请求使用同一个 requestQueue,而不是每次都new出来。
因为new出一个requestQueue后,队里中会默认有5个线程在一直等待任务的加入。我们只需要每次把新的请求 add进去即可 requestQueue.add(stringRequest);
如果每次都new出一个queue会浪费大量资源。
本篇总结:
1、new出一个队列 requestQueue
2、new出一个合适的request
3、把request加入(add)到队列中去执行
4、requestQueue 只建议new一次,也就是在app中,只维护一个requestqueue,之后的网络请求都是往此队列中添加request即可。
5、requestQueue 默认是5个线程,缓存一个,网络请求4个,可以根据自己需求添加或减少。