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. 解决触摸屏设备click事件300ms的延迟的问题

    从点击屏幕上的元素到触发元素的 click 事件,移动浏览器(触摸屏)会有大约 300 毫秒的等待时间.为什么这么设计呢? 因为它想看看你是不是要进行双击(double tap)操作.300ms的等待 ...

  2. 转 nutch网页快照乱码解决方法

    修改apache-tomcat-7.0.55\webapps\nutch-1.2下的cached.jsp 将content = new String(bean.getContent(details)) ...

  3. 第三章 Git的入门 - 读书笔记

    Android驱动月考3 第三章 Git的入门 - 读书笔记 对于Github,这是全世界最大的开源平台,你可以把你做的项目在这里开源,把你发现的一些新技术在这里开源,向全世界的开发者们分享,大家都彼 ...

  4. AX7: HOW TO USE TABLE METHOD EXTENSION CLASS

    To create new methods on a table without customize you should use the Table method extension class. ...

  5. js实现表单验证 常用JS表单验证

    CSS代码 @charset "gb2312"; /* CSS Document */ body,dl,dt,dd,div,form {padding:;margin:;} #he ...

  6. 安装mysql步骤

    1.yum install lrzsz 安装上传功能2.查看系统是否装有MySql  :rpm -qa | grep mysql3.查看系统Mysql位置 :whereis mysql4.卸载Mysq ...

  7. MS AX 技术相关网站收藏

    Microsoft Dynamics AX Developer Centerhttps://msdn.microsoft.com/en-us/dynamics/ax/default.aspx From ...

  8. 仿google art图片预览算法及demo(iphone/安卓版本)

    演示地址:用手机扫描二维码(手机端浏览) 功能:双击放大,单指操作拖动,双指操作放大缩小.

  9. Welcome to China

    subway, railway, highway ,way way to dieofficer,announcer, professor, sir sir to lieWelcome to China

  10. synchronized锁重入

    package synLockIn_1; /* synchronized锁重入,当一个线程得到一个对象锁且还未释放锁时,再次请求此对象锁时可以再次得到该对象的锁 * 此例中线程1进入Service类的 ...