android的volley框架

1.Volley概述

在项目开发过程中,博主曾写过大量的访问网络重复代码,特别是ListView adapter很难避免getView()方法不被重复调用,如果ImageView不利用缓存机制,那么网络的负荷就会更大!曾将访问网络代码和缓存封装起来使用,但是中间仍存在不少瑕疵!今年的Google I/O 2013上,Volley发布了!Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮


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

2.Volley源码分析

(1).Volley.java

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

[java] view plain copy
  1. /** 
  2.  * @author zimo2013 
  3.  * @see http://blog.csdn.net/zimo2013 
  4.  */  
  5. public static RequestQueue newRequestQueue(Context context, HttpStack stack) {  
  6.     File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);  
  7.   
  8.     String userAgent = "volley/0";  
  9.     try {  
  10.         String packageName = context.getPackageName();  
  11.         PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);  
  12.         userAgent = packageName + "/" + info.versionCode;  
  13.     } catch (NameNotFoundException e) {  
  14.     }  
  15.   
  16.     if (stack == null) {  
  17.         if (Build.VERSION.SDK_INT >= 9) {  
  18.             stack = new HurlStack();  
  19.         } else {  
  20.             stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));  
  21.         }  
  22.     }  
  23.   
  24.     Network network = new BasicNetwork(stack);  
  25.   
  26.     //cacheDir 缓存路径 /data/data//cache/  
  27.     RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);  
  28.     queue.start();  
  29.     /* 
  30.      * 实例化一个RequestQueue,其中start()主要完成相关工作线程的开启, 
  31.      * 比如开启缓存线程CacheDispatcher先完成缓存文件的扫描, 还包括开启多个NetworkDispatcher访问网络线程, 
  32.      * 该多个网络线程将从 同一个 网络阻塞队列中读取消息 
  33.      *  
  34.      * 此处可见,start()已经开启,所有我们不用手动的去调用该方法,在start()方法中如果存在工作线程应该首先终止,并重新实例化工作线程并开启 
  35.      * 在访问网络很频繁,而又重复调用start(),势必会导致性能的消耗;但是如果在访问网络很少时,调用stop()方法,停止多个线程,然后调用start(),反而又可以提高性能,具体可折中选择 
  36.      */  
  37.   
  38.     return queue;  
  39. }  

(2).RequestQueue.java

[java] view plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  1. public class StringRequest extends Request {  
  2.     private final Listener 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 listener,  
  13.             ErrorListener errorListener) {  
  14.         super(method, url, errorListener);  
  15.         mListener = listener;  
  16.     }  
  17.   
  18.     public StringRequest(String url, Listener 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 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 plain copy
  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, nullnull);  
  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() {  
  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 plain copy
  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 plain copy
  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. }

你可能感兴趣的:(android封装的框架)