码迷,mamicode.com
首页 > 移动开发 > 详细

Android开源框架——Volley

时间:2015-05-26 00:09:01      阅读:415      评论:0      收藏:0      [点我收藏+]

标签:

      Volley 是 Google 在 2013 I/O 大会上推出的 Android 异步网络请求框架和图片加载框架。特别适合数据量小,通信频繁的网络操作。Volley 主要是通过两种 Diapatch Thread 不断从 RequestQueue 中取出请求,根据是否已缓存调用 Cache 或 Network 这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据,然后交由 ResponseDelivery 去做结果分发及回调处理。

原文链接:http://blog.csdn.net/zimo2013/article/details/16971253

Volley特别适合数据量不大但是通信频繁的场景,现在android提供的源码已经包含Volley,以后在项目中,可以根据需求引入Volley jar文件!

  

2.Volley源码分析

(1).Volley.java

Volley.newRequestQueue()方法在一个app最好执行一次,可以使用单例设计模式或者在application完成初始化,具体原因请查看代码分析 

[java] view plaincopy技术分享技术分享 
  1. /** 
  2.  * @author zimo2013 
  3.  * @see http://blog.csdn.net/zimo2013 
  4.  */  
  5. //请求消息队列:RequestQueue;
  6. public static RequestQueue newRequestQueue(Context context, HttpStack stack) {  
  7.     File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);  //新建对应的缓存目录
  8.   
  9.     String userAgent = "volley/0";  //声明一个默认的字符串;
  10.     try {  
  11.         String packageName = context.getPackageName();  
  12.         PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);  
  13.         userAgent = packageName + "/" + info.versionCode;  //设置该字符串为:包名+应用的版本号
  14.     } catch (NameNotFoundException e) {  
  15.     }  
  16.   
    A RequestQueue needs two things to do its job: a network to perform transport of the requests(一个网络进行传输的请求), and a cache to handle caching. There are standard implementations of these available in 
    the Volley toolbox: (有这些可用的标准实现Volley toolbox)
    DiskBasedCache provides a one-file-per-response cache with an in-memory index, 
    and BasicNetwork providesa network transport based on your choice of AndroidHttpClient or HttpURLConnection.(DiskBasedCache one-file-per-response缓存提供了一个内存中的指数,并根据您选择BasicNetwork提供了一个网络传输
    AndroidHttpClient或HttpURLConnection。)
  17. BasicNetwork is Volley‘s default network implementation. A BasicNetwork must be initialized with the HTTP client your app is using to connect to the network. Typically this is AndroidHttpClient or HttpURLConnection:

    Use AndroidHttpClient for apps targeting Android API levels lower than API Level 9 (Gingerbread). Prior to Gingerbread, HttpURLConnection was unreliable. For more discussion of this topic, see Android‘s HTTP Clients.
    
    
    Use HttpURLConnection for apps targeting Android API Level 9 (Gingerbread) and higher.
    To create an app that runs on all versions of Android, you can check the version of Android the device is running and choose the appropriate HTTP client, for example:

    HttpStack stack; ...
    // If the device is running a version >= Gingerbread... if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { // ...use HttpURLConnection for stack. } else { // ...use AndroidHttpClient for stack. } Network network = new BasicNetwork(stack);

     

  18.     if (stack == null) {  
  19.         if (Build.VERSION.SDK_INT >= 9) {  
  20.             stack = new HurlStack();  
  21.         } else {  
  22.             stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));  
  23.         }  
  24.     }  
  25.   
  26.     Network network = new BasicNetwork(stack);  
  27.   
  28.     //cacheDir 缓存路径 /data/data/<pkg name>/cache/<name>  
  29.     RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);  
  30.     queue.start();  
  31.     /* 
  32.      * 实例化一个RequestQueue,其中start()主要完成相关工作线程的开启, 
  33.      * 比如开启缓存线程CacheDispatcher先完成缓存文件的扫描, 还包括开启多个NetworkDispatcher访问网络线程, 
  34.      * 该多个网络线程将从 同一个 网络阻塞队列中读取消息 
  35.      *  
  36.      * 此处可见,start()已经开启,所有我们不用手动的去调用该方法,在start()方法中如果存在工作线程应该首先终止,并重新实例化工作线程并开启 
  37.      * 在访问网络很频繁,而又重复调用start(),势必会导致性能的消耗;但是如果在访问网络很少时,调用stop()方法,停止多个线程,然后调用start(),反而又可以提高性能,具体可折中选择 
  38.      */  
  39.   
  40.     return queue;  
  41. }  

(2).RequestQueue.java

[java] view plaincopy技术分享技术分享
 
  1. /** 
  2.  * RequestQueue类存在2个非常重要的PriorityBlockingQueue类型的成员字段mCacheQueue mNetworkQueue ,该PriorityBlockingQueue为java1.5并发库提供的新类 
  3.  * 其中有几个重要的方法,比如take()为从队列中取得对象,如果队列不存在对象,将会被阻塞,直到队列中存在有对象,类似于Looper.loop() 
  4.  *  
  5.  * 实例化一个request对象,调用RequestQueue.add(request),该request如果不允许被缓存,将会被添加至mNetworkQueue队列中,待多个NetworkDispatcher线程take()取出对象 
  6.  * 如果该request可以被缓存,该request将会被添加至mCacheQueue队列中,待mCacheDispatcher线程从mCacheQueue.take()取出对象, 
  7.  * 如果该request在mCache中不存在匹配的缓存时,该request将会被移交添加至mNetworkQueue队列中,待网络访问完成后,将关键头信息添加至mCache缓存中去! 
  8.  *  
  9.  * @author zimo2013 
  10.  * @see http://blog.csdn.net/zimo2013 
  11.  */  
  12. public void start() {  
  13.     stop();  
  14.       
  15.     mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);  
  16.     mCacheDispatcher.start();  
  17.   
  18.     // Create network dispatchers (and corresponding threads) up to the pool size.  
  19.     for (int i = 0; i < mDispatchers.length; i++) {  
  20.         NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,  
  21.                 mCache, mDelivery);  
  22.         mDispatchers[i] = networkDispatcher;  
  23.         networkDispatcher.start();  
  24.     }  
  25. }  

 (3).CacheDispatcher.java

[java] view plaincopy技术分享技术分享
 
  1. /** 
  2.  * @author zimo2013 
  3.  * @see http://blog.csdn.net/zimo2013 
  4.  */  
  5. @Override  
  6. public void run() {  
  7.     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  8.   
  9.     //缓存初始化,会遍历整个缓存文件夹  
  10.     mCache.initialize();  
  11.     {  
  12.         //执行代码  
  13.         /*if (!mRootDirectory.exists()) { 
  14.             if (!mRootDirectory.mkdirs()) { 
  15.                 VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath()); 
  16.             } 
  17.             return; 
  18.         } 
  19.  
  20.         File[] files = mRootDirectory.listFiles(); 
  21.         if (files == null) { 
  22.             return; 
  23.         } 
  24.         for (File file : files) { 
  25.             FileInputStream fis = null; 
  26.             try { 
  27.                 fis = new FileInputStream(file); 
  28.                 CacheHeader entry = CacheHeader.readHeader(fis); 
  29.                 entry.size = file.length(); 
  30.                 putEntry(entry.key, entry); 
  31.             } catch (IOException e) { 
  32.                 if (file != null) { 
  33.                    file.delete(); 
  34.                 } 
  35.             } finally { 
  36.                 try { 
  37.                     if (fis != null) { 
  38.                         fis.close(); 
  39.                     } 
  40.                 } catch (IOException ignored) { } 
  41.             } 
  42.         }*/  
  43.     }  
  44.   
  45.     while (true) {  
  46.         try {  
  47.             //该方法可能会被阻塞  
  48.             final Request request = mCacheQueue.take();  
  49.   
  50.             Cache.Entry entry = mCache.get(request.getCacheKey());  
  51.             if (entry == null) {  
  52.                 //缓存不存在,则将该request添加至网络队列中  
  53.                 mNetworkQueue.put(request);  
  54.                 continue;  
  55.             }  
  56.   
  57.             //是否已经过期  
  58.             if (entry.isExpired()) {  
  59.                 request.setCacheEntry(entry);  
  60.                 mNetworkQueue.put(request);  
  61.                 continue;  
  62.             }  
  63.   
  64.             Response<?> response = request.parseNetworkResponse(  
  65.                     new NetworkResponse(entry.data, entry.responseHeaders));  
  66.   
  67.             //存在缓存,执行相关操作  
  68.   
  69.         } catch (InterruptedException e) {  
  70.         }  
  71.     }  
  72. }  

(4).NetworkDispatcher.java

[java] view plaincopy技术分享技术分享
 
  1. /** 
  2.  * @author zimo2013 
  3.  * @see http://blog.csdn.net/zimo2013 
  4.  */  
  5. @Override  
  6. public void run() {  
  7.     Request request;  
  8.     while (true) {  
  9.         try {  
  10.             //可能会被  
  11.             request = mQueue.take();  
  12.         } catch (InterruptedException e) {  
  13.             // We may have been interrupted because it was time to quit.  
  14.             if (mQuit) {  
  15.                 return;  
  16.             }  
  17.             continue;  
  18.         }  
  19.   
  20.         try {  
  21.               
  22.             //访问网络,得到数据  
  23.             NetworkResponse networkResponse = mNetwork.performRequest(request);  
  24.   
  25.             if (networkResponse.notModified && request.hasHadResponseDelivered()) {  
  26.                 request.finish("not-modified");  
  27.                 continue;  
  28.             }  
  29.   
  30.             // Parse the response here on the worker thread.  
  31.             Response<?> response = request.parseNetworkResponse(networkResponse);  
  32.   
  33.             // 写入缓存  
  34.             if (request.shouldCache() && response.cacheEntry != null) {  
  35.                 mCache.put(request.getCacheKey(), response.cacheEntry);  
  36.                 request.addMarker("network-cache-written");  
  37.             }  
  38.   
  39.             // Post the response back.  
  40.             request.markDelivered();  
  41.             mDelivery.postResponse(request, response);  
  42.         } catch (VolleyError volleyError) {  
  43.             parseAndDeliverNetworkError(request, volleyError);  
  44.         } catch (Exception e) {  
  45.             VolleyLog.e(e, "Unhandled exception %s", e.toString());  
  46.             mDelivery.postError(request, new VolleyError(e));  
  47.         }  
  48.     }  
  49. }  

(5).StringRequest.java

其中在parseNetworkResponse()中,完成将byte[]到String的转化,可能会出现字符乱码,HttpHeaderParser.parseCharset(response.headers)方法在尚未指定是返回为ISO-8859-1,可以修改为utf-8
[java] view plaincopy技术分享技术分享
 
  1. public class StringRequest extends Request<String> {  
  2.     private final Listener<String> mListener;  
  3.   
  4.     /** 
  5.      * Creates a new request with the given method. 
  6.      * 
  7.      * @param method the request {@link Method} to use 
  8.      * @param url URL to fetch the string at 
  9.      * @param listener Listener to receive the String response 
  10.      * @param errorListener Error listener, or null to ignore errors 
  11.      */  
  12.     public StringRequest(int method, String url, Listener<String> listener,  
  13.             ErrorListener errorListener) {  
  14.         super(method, url, errorListener);  
  15.         mListener = listener;  
  16.     }  
  17.   
  18.     public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {  
  19.         this(Method.GET, url, listener, errorListener);  
  20.     }  
  21.   
  22.     @Override  
  23.     protected void deliverResponse(String response) {  
  24.         mListener.onResponse(response);  
  25.     }  
  26.   
  27.     @Override  
  28.     protected Response<String> parseNetworkResponse(NetworkResponse response) {  
  29.         String parsed;  
  30.         try {  
  31.             //将data字节数据转化为String对象  
  32.             parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));  
  33.         } catch (UnsupportedEncodingException e) {  
  34.             parsed = new String(response.data);  
  35.         }  
  36.         //返回Response对象,其中该对象包含访问相关数据  
  37.         return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));  
  38.     }  
  39. }  

(6).ImageLoader.java

[java] view plaincopy技术分享技术分享
 
  1. /** 
  2.  * @author zimo2013 
  3.  * @see http://blog.csdn.net/zimo2013 
  4.  */  
  5. public ImageContainer get(String requestUrl, ImageListener imageListener,  
  6.         int maxWidth, int maxHeight) {  
  7.     throwIfNotOnMainThread();  
  8.     final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);  
  9.   
  10.     //从mCache得到bitmap对象,因此可以覆写ImageCache,完成图片的三级缓存,即在原有的LruCache添加一个软引用缓存  
  11.     Bitmap cachedBitmap = mCache.getBitmap(cacheKey);  
  12.     if (cachedBitmap != null) {  
  13.         //得到缓存对象  
  14.         ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);  
  15.         imageListener.onResponse(container, true);  
  16.         return container;  
  17.     }  
  18.   
  19.     ImageContainer imageContainer =  
  20.             new ImageContainer(null, requestUrl, cacheKey, imageListener);  
  21.   
  22.     // 首先更新该view,其指定了defaultImage  
  23.     imageListener.onResponse(imageContainer, true);  
  24.   
  25.     // 根据可以去检查该请求是否已经发起过  
  26.     BatchedImageRequest request = mInFlightRequests.get(cacheKey);  
  27.     if (request != null) {  
  28.         request.addContainer(imageContainer);  
  29.         return imageContainer;  
  30.     }  
  31.   
  32.     Request<?> newRequest =  
  33.         new ImageRequest(requestUrl, new Listener<Bitmap>() {  
  34.             @Override  
  35.             public void onResponse(Bitmap response) {  
  36.                 //如果请求成功  
  37.                 onGetImageSuccess(cacheKey, response);  
  38.             }  
  39.         }, maxWidth, maxHeight,  
  40.         Config.RGB_565, new ErrorListener() {  
  41.             @Override  
  42.             public void onErrorResponse(VolleyError error) {  
  43.                 onGetImageError(cacheKey, error);  
  44.             }  
  45.         });  
  46.     //添加至请求队列中  
  47.     mRequestQueue.add(newRequest);  
  48.     //同一添加进map集合,以方便检查该request是否正在请求网络,可以节约资源  
  49.     mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer));  
  50.     return imageContainer;  
  51. }  
[java] view plaincopy技术分享技术分享
 
  1. private void onGetImageSuccess(String cacheKey, Bitmap response) {  
  2.     //缓存对象  
  3.     mCache.putBitmap(cacheKey, response);  
  4.   
  5.     // 请求完成,不需要检测  
  6.     BatchedImageRequest request = mInFlightRequests.remove(cacheKey);  
  7.   
  8.     if (request != null) {  
  9.         request.mResponseBitmap = response;  
  10.         //处理结果  
  11.         batchResponse(cacheKey, request);  
  12.     }  
  13. }  
[java] view plaincopy技术分享技术分享
 
  1. private void batchResponse(String cacheKey, BatchedImageRequest request) {  
  2.     mBatchedResponses.put(cacheKey, request);  
  3.     //通过handler,发送一个操作  
  4.     if (mRunnable == null) {  
  5.         mRunnable = new Runnable() {  
  6.             @Override  
  7.             public void run() {  
  8.                 for (BatchedImageRequest bir : mBatchedResponses.values()) {  
  9.                     for (ImageContainer container : bir.mContainers) {  
  10.                         if (container.mListener == null) {  
  11.                             continue;  
  12.                         }  
  13.                         if (bir.getError() == null) {  
  14.                             container.mBitmap = bir.mResponseBitmap;  
  15.                             //更新结果  
  16.                             container.mListener.onResponse(container, false);  
  17.                         } else {  
  18.                             container.mListener.onErrorResponse(bir.getError());  
  19.                         }  
  20.                     }  
  21.                 }  
  22.                 mBatchedResponses.clear();  
  23.                 mRunnable = null;  
  24.             }  
  25.   
  26.         };  
  27.         // mHandler对应的looper是MainLooper,因此被MainLooper.loop()得到该message,故该runnable操作在主线程中执行,  
  28.         mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);  
  29.     }  
  30. }  

3.总结

 

技术分享

RequestQueue类存在2个非常重要的PriorityBlockingQueue类型的成员字段mCacheQueue mNetworkQueue ,该PriorityBlockingQueue为java1.5并发库提供的!其中有几个重要的方法,比如take()为从队列中取得对象,如果队列不存在对象,将会被阻塞,直到队列中存在有对象,类似于Looper.loop()。实例化一个request对象,调用RequestQueue.add(request),该request如果不允许被缓存,将会被添加至mNetworkQueue队列中,待多个NetworkDispatcher线程从mNetworkQueue中take()取出对象。如果该request可以被缓存,该request将会被添加至mCacheQueue队列中,待mCacheDispatcher线程从mCacheQueue.take()取出对象,如果该request在mCache中不存在匹配的缓存时,该request将会被移交添加至mNetworkQueue队列中,待网络访问完成后,将关键头信息添加至mCache缓存中去,并通过ResponseDelivery主线程调用request的相关方法!

Android开源框架——Volley

标签:

原文地址:http://www.cnblogs.com/liyanli-mu640065/p/4529268.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!