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

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

Volley提供的功能
简单来说,它提供了如下的便利功能:

    • JSON,图像等的异步下载;
    • 网络请求的排序(scheduling)
    • 网络请求的优先级处理
    • 缓存
    • 多级别取消请求
    • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)
注意:该框架也有不实用的地方,比如大数据(large payloads ),流媒体,这些case,还需要使用原始的方法,比如Download Manager等。

1.使用步骤:

引入Volley非常简单,首先,从git库先克隆一个下来:

1

git clone https://android.googlesource.com/platform/frameworks/volley

然后编译为jar包,再在自己的工程里import进来。

注意,这个库要求最低SDK版本为Froyo,即至少要设置android:minSdkVersion为8以上。

扩展:Android 2.2系统代号—Froyo

北京时间2010年1月18日上午消息,据国外媒体今日报道,谷歌Android高级产品经理埃里克·曾(Erick Tseng)表示,新版Android操作系统被命名为“Froyo”。
“Froyo”是英文“frozen yogurt”的缩写,意为“冻酸奶”。谷歌Android此前的一些版本曾经采用过“Cupcakes”(杯形蛋糕)、“Donuts”(甜甜圈)、“Eclairs”(长形松饼)三个食品名称。这些名称的首字母遵循了C、D、E、F的顺序。
已介绍的功能,包括:
* JIT compiler(即时编译技术,可以极大地提高系统的运行速度)
* 支援V8的Chrome浏览器(V8是JS引擎,它同样也用到了上面提到的JIT技术)
* 新增无线网路/ USB 共享功能(Tethering & Protable Hotspot)
* Flash Player 10.1 & Flash Air开发工具
* Android软件自动更新功能
* 与iTunes及Windows Media进行同步
* 以Over-the-air方式安装Android软件
* 将程序安装在SD卡上
提升2-5倍Android软件的运行速度
官方人员在会场上利用Nexus One运行横向游戏Replica Island,展示Android 2.1(Eclair)及Android 2.2(Froyo)的FPS情况,从结果显示,支持JIT compiler的Froyo持续高于30FPS,而Éclair 则降至20FPS,可见支持JIT compiler的Froyo,让Android系统突然强大起来,真令人兴奋。

  

 

2.Volley源码分析

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

(1).Volley.java

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

  1. //请求消息队列:RequestQueue;
  2. public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
  3. File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);  //新建对应的缓存目录
  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. 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。)
  12. 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(姜饼
    Android2.3)). Prior to Gingerbread, HttpURLConnection was unreliable(不可靠的,对比rely:v依靠). 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);
  13. if (stack == null) {
  14. if (Build.VERSION.SDK_INT >= 9) {
  15. stack = new HurlStack();
  16. } else {
  17. stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
  18. }
  19. }
  20. Network network = new BasicNetwork(stack);
  21. //cacheDir 缓存路径 /data/data/<pkg name>/cache/<name>
  22. RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
  23. queue.start();
  24. /*
  25. * 实例化一个RequestQueue,其中start()主要完成相关工作线程的开启,
  26. * 比如开启缓存线程CacheDispatcher先完成缓存文件的扫描, 还包括开启多个NetworkDispatcher访问网络线程,
  27. * 该多个网络线程将从 同一个 网络阻塞队列中读取消息
  28. *
  29. * 此处可见,start()已经开启,所有我们不用手动的去调用该方法,在start()方法中如果存在工作线程应该首先终止,并重新实例化工作线程并开启
  30. * 在访问网络很频繁,而又重复调用start(),势必会导致性能的消耗;但是如果在访问网络很少时,调用stop()方法,停止多个线程,然后调用start(),反而又可以提高性能,具体可折中选择
  31. */
  32. return queue;
  33. }

(2).RequestQueue.java

  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. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
  15. mCacheDispatcher.start();
  16. // Create network dispatchers (and corresponding threads) up to the pool size.
  17. for (int i = 0; i < mDispatchers.length; i++) {
  18. NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
  19. mCache, mDelivery);
  20. mDispatchers[i] = networkDispatcher;
  21. networkDispatcher.start();
  22. }
  23. }

(3).CacheDispatcher.java

  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. mCache.initialize();
  10. {
  11. //执行代码
  12. /*if (!mRootDirectory.exists()) {
  13. if (!mRootDirectory.mkdirs()) {
  14. VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());
  15. }
  16. return;
  17. }
  18. File[] files = mRootDirectory.listFiles();
  19. if (files == null) {
  20. return;
  21. }
  22. for (File file : files) {
  23. FileInputStream fis = null;
  24. try {
  25. fis = new FileInputStream(file);
  26. CacheHeader entry = CacheHeader.readHeader(fis);
  27. entry.size = file.length();
  28. putEntry(entry.key, entry);
  29. } catch (IOException e) {
  30. if (file != null) {
  31. file.delete();
  32. }
  33. } finally {
  34. try {
  35. if (fis != null) {
  36. fis.close();
  37. }
  38. } catch (IOException ignored) { }
  39. }
  40. }*/
  41. }
  42. while (true) {
  43. try {
  44. //该方法可能会被阻塞
  45. final Request request = mCacheQueue.take();
  46. Cache.Entry entry = mCache.get(request.getCacheKey());
  47. if (entry == null) {
  48. //缓存不存在,则将该request添加至网络队列中
  49. mNetworkQueue.put(request);
  50. continue;
  51. }
  52. //是否已经过期
  53. if (entry.isExpired()) {
  54. request.setCacheEntry(entry);
  55. mNetworkQueue.put(request);
  56. continue;
  57. }
  58. Response<?> response = request.parseNetworkResponse(
  59. new NetworkResponse(entry.data, entry.responseHeaders));
  60. //存在缓存,执行相关操作
  61. } catch (InterruptedException e) {
  62. }
  63. }
  64. }

(4).NetworkDispatcher.java

  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. try {
  20. //访问网络,得到数据
  21. NetworkResponse networkResponse = mNetwork.performRequest(request);
  22. if (networkResponse.notModified && request.hasHadResponseDelivered()) {
  23. request.finish("not-modified");
  24. continue;
  25. }
  26. // Parse the response here on the worker thread.
  27. Response<?> response = request.parseNetworkResponse(networkResponse);
  28. // 写入缓存
  29. if (request.shouldCache() && response.cacheEntry != null) {
  30. mCache.put(request.getCacheKey(), response.cacheEntry);
  31. request.addMarker("network-cache-written");
  32. }
  33. // Post the response back.
  34. request.markDelivered();
  35. mDelivery.postResponse(request, response);
  36. } catch (VolleyError volleyError) {
  37. parseAndDeliverNetworkError(request, volleyError);
  38. } catch (Exception e) {
  39. VolleyLog.e(e, "Unhandled exception %s", e.toString());
  40. mDelivery.postError(request, new VolleyError(e));
  41. }
  42. }
  43. }

(5).StringRequest.java

其中在parseNetworkResponse()中,完成将byte[]到String的转化,可能会出现字符乱码,HttpHeaderParser.parseCharset(response.headers)方法在尚未指定是返回为ISO-8859-1,可以修改为utf-8

  1. public class StringRequest extends Request<String> {
  2. private final Listener<String> mListener;
  3. /**
  4. * Creates a new request with the given method.
  5. *
  6. * @param method the request {@link Method} to use
  7. * @param url URL to fetch the string at
  8. * @param listener Listener to receive the String response
  9. * @param errorListener Error listener, or null to ignore errors
  10. */
  11. public StringRequest(int method, String url, Listener<String> listener,
  12. ErrorListener errorListener) {
  13. super(method, url, errorListener);
  14. mListener = listener;
  15. }
  16. public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
  17. this(Method.GET, url, listener, errorListener);
  18. }
  19. @Override
  20. protected void deliverResponse(String response) {
  21. mListener.onResponse(response);
  22. }
  23. @Override
  24. protected Response<String> parseNetworkResponse(NetworkResponse response) {
  25. String parsed;
  26. try {
  27. //将data字节数据转化为String对象
  28. parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
  29. } catch (UnsupportedEncodingException e) {
  30. parsed = new String(response.data);
  31. }
  32. //返回Response对象,其中该对象包含访问相关数据
  33. return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
  34. }
  35. }

(6).ImageLoader.java

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

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的相关方法!

推荐文章:http://www.cnblogs.com/bvin/p/3286908.html

http://blog.csdn.net/zimo2013/article/details/16981945

Android开源框架——Volley的更多相关文章

  1. Android开源框架Volley(Google IO 2013)源代码及内部实现分析

    1.Volley概述 在项目开发过 程中,博主曾写过大量的访问网络重复代码,特别是ListView adapter很难避免getView()方法不被重复调用,如果ImageView不利用缓存机制,那么 ...

  2. [Android] 开源框架 Volley 自定义 Request

    今天在看Volley demo (https://github.com/smanikandan14/Volley-demo), 发现自定义GsonRequest那块代码不全, 在这里贴一个全的. pu ...

  3. android 开源框架推荐

    同事整理的 android 开源框架,个个都堪称经典.32 个赞! 1.volley 项目地址 https://github.com/smanikandan14/Volley-demo (1)  JS ...

  4. 开源框架Volley的使用《一》

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/52785378 本 ...

  5. 六款值得推荐的Android开源框架简介

    技术不再多,知道一些常用的.不错的就够了.下面就是最近整理的“性价比”比较高的Android开源框架,应该是相对实用的. 1.volley 项目地址 https://github.com/smanik ...

  6. Android 开源框架Universal-Image-Loader学习

    Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用 Android 开源框架Universal-Image-Loader完全解析(二)--- 图片 ...

  7. Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/39057201),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...

  8. Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...

  9. Android进阶笔记13:RoboBinding(实现了数据绑定 Presentation Model(MVVM) 模式的Android开源框架)

    1.RoboBinding RoboBinding是一个实现了数据绑定 Presentation Model(MVVM) 模式的Android开源框架.从简单的角度看,他移除了如addXXListen ...

随机推荐

  1. SpringMVC配置项学习笔记

    1. <mvc:annotation-driven /> <mvc:annotation-driven />是一种简写形式,默认会注册DefaultAnnotationHand ...

  2. hadoop入门(2)&mdash;&mdash;HDFS2.0应用场景、原理、基本架构及使用方法

    一.HDFS概述         优点:高容错性.适合批处理.适合大数据处理.流式文件访问:一次写入,多次读取.         缺点:不适合低延迟数据访问.不适合小文件存取(受限于NameNode) ...

  3. WCF安全2-非对称加密

    概述: 数字签名和加密依赖于相应的加密算法 自变量:加密前的数据.密钥 因变量:加密后的数据 加密算法分类:根据加密和解密这两种步骤采用的密钥的是否相同进行分类 相同:对称加密 不相同:非对称加密 非 ...

  4. Java Hour 30 Weather ( 3 )

    有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. Hour 30 上回终点 Model 这里有一些java bean 的 风格约 ...

  5. CSS框模型(框模型概述、内边距、边框、外边距、外边距合并)

    CSS 框模型概述 CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边距.边框 和 外边距 的方式. 元素框的最内部分是实际的内容,直接包围内容的是内边距.内边距呈现了元素的背景. ...

  6. Android开发之BroadcastReceiver的使用

    1.静态注册. 在manifest中注册. <receiver android:name="com.exce.learnbroadcastreceiver.MyReceiver&quo ...

  7. SQL Server 2000的安全配置

    SQL Server 2000的安全配置 数据库是电子商务.金融连同ERP系统的基础,通常都保存着重要的商业伙伴和客户信息.大多数企业.组织连同政府 部门的电子数据都保存在各种数据库中,他们用这些数据 ...

  8. Qt中的坐标系统

    Qt使用统一的坐标系统来定位窗口部件的位置和大小. 以屏幕的左上角为原点即(0, 0)点,从左向右为x轴正向,从上向下为y轴正向,这整个屏幕的坐标系统就用来定位顶层窗口: 此外,窗口内部也有自己的坐标 ...

  9. MLDS笔记:浅层结构 vs 深层结构

    深度学习出现之前,机器学习方面的开发者通常需要仔细地设计特征.设计算法,且他们在理论上常能够得知这样设计的实际表现如何: 深度学习出现后,开发者常先尝试实验,有时候实验结果常与直觉相矛盾,实验后再找出 ...

  10. zxing二维码的生成与解码(C#)

    ZXing是一个开源Java类库用于解析多种格式的1D/2D条形码.目标是能够对QR编码.Data Matrix.UPC的1D条形码进行解码. 其提供了多种平台下的客户端包括:J2ME.J2SE和An ...