Volley 是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如:
  • android-async-http

  • retrofit

  • okhttp

他们各有优劣,之前个人则比较喜欢用android-async-http, 如今Google推出了官方的针对Android平台上的网络通信库,能使网络通信更快,更简单,更健壮,Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求, 我们没有理由不跟上时代的潮流

使用Volley

下载Volley源码并build jar包。

$ git clone https://android.googlesource.com/platform/frameworks/volley $ cd volley $ android update project -p $ ant jar 

然后把生成的jar包引用到我们的项目中,extras目录下则包含了目前最新的volley源码。

说明

此Demo主要介绍了日常网络开发常用的基本功能,但volley的扩展性很强,可以根据需要定制你自己的网络请求。

volley视频地址:http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded


以上是在Google IO的演讲上ppt的配图,从上面这张图我们可以看出,volley适合快速,简单的请求(Json对象,图片加载)。

volley的特性:

  • JSON,图像等的异步下载;
  • 网络请求的排序(scheduling)
  • 网络请求的优先级处理
  • 缓存
  • 多级别取消请求
  • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)

接下来,我们来学习简单的使用下volley给我提供的API吧。

1.首先拿到一个请求队列(RequestQueue只需要一个实例即可,不像AsyncTask每次使用都要new一个)

[java] view plain copy
  1. //初始化RequestQueue一个activity只需要一个
  2. privatevoidinitRequestQueue(){
  3. mQueue=Volley.newRequestQueue(getApplicationContext());
  4. }

2.实现volley的异步请求类(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest

由于用法都相差不大,我就不一一举例了,举几个常用有代表性的例子:

以下代码是StringRequest的get请求:

[java] view plain copy
  1. //get请求
[java] view plain copy
  1. privatevoidloadGetStr(Stringurl){
  2. StringRequestsrReq=newStringRequest(Request.Method.GET,url,
  3. newStrListener(),newStrErrListener()){
  4. protectedfinalStringTYPE_UTF8_CHARSET="charset=UTF-8";
  5. //重写parseNetworkResponse方法改变返回头参数解决乱码问题
  6. //主要是看服务器编码,如果服务器编码不是UTF-8的话那么就需要自己转换,反之则不需要
  7. @Override
  8. protectedResponse<String>parseNetworkResponse(
  9. NetworkResponseresponse){
  10. try{
  11. Stringtype=response.headers.get(HTTP.CONTENT_TYPE);
  12. if(type==null){
  13. type=TYPE_UTF8_CHARSET;
  14. response.headers.put(HTTP.CONTENT_TYPE,type);
  15. }elseif(!type.contains("UTF-8")){
  16. type+=";"+TYPE_UTF8_CHARSET;
  17. response.headers.put(HTTP.CONTENT_TYPE,type);
  18. }
  19. }catch(Exceptione){
  20. }
  21. returnsuper.parseNetworkResponse(response);
  22. }
  23. };
  24. srReq.setShouldCache(true);//控制是否缓存
  25. startVolley(srReq);
  26. }

以下代码是 JsonObjectRequest的post 请求: [java] view plain copy
  1. //post请求
  2. privatevoidloadPostJson(Stringurl){
  3. //第二个参数说明:
  4. //ConstructorwhichdefaultstoGETifjsonRequestisnull,POST
  5. //otherwise.
  6. //默认情况下设成null为get方法,否则为post方法。
  7. JsonObjectRequestsrReq=newJsonObjectRequest(url,null,
  8. newJsonListener(),newStrErrListener()){
  9. @Override
  10. protectedMap<String,String>getParams()throwsAuthFailureError{
  11. Map<String,String>map=newHashMap<String,String>();
  12. map.put("w","2459115");
  13. map.put("u","f");
  14. returnmap;
  15. }
  16. };
  17. srReq.setShouldCache(false);//控制是否缓存
  18. startVolley(srReq);
  19. }

大家注意看的话,无论是 JsonObjectReques的postt还是StringRequest的get都需要传入两个监听函数一个是成功一个是失败,成功监听他们会返回相应类型的数据:

[java] view plain copy
  1. //Str请求成功回调
  2. privateclassStrListenerimplementsListener<String>{
  3. @Override
  4. publicvoidonResponse(Stringarg0){
  5. Log.e(Tag,arg0);
  6. }
  7. }
  8. //Gson请求成功回调
  9. privateclassGsonListenerimplementsListener<ErrorRsp>{
  10. @Override
  11. publicvoidonResponse(ErrorRsparg0){
  12. Toast.makeText(mContext,arg0.toString(),Toast.LENGTH_LONG).show();
  13. }
  14. }
  15. //共用失败回调
  16. privateclassStrErrListenerimplementsErrorListener{
  17. @Override
  18. publicvoidonErrorResponse(VolleyErrorarg0){
  19. Toast.makeText(mContext,
  20. VolleyErrorHelper.getMessage(arg0,mContext),
  21. Toast.LENGTH_LONG).show();
  22. }
  23. }
接下来是 ImageRequest [java] view plain copy
  1. /**
  2. *第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,
  3. *指定成0的话就表示不管图片有多大,都不会进行压缩。
  4. *
  5. *@paramurl
  6. *图片地址
  7. *@paramlistener
  8. *@parammaxWidth
  9. *指定允许图片最大的宽度
  10. *@parammaxHeight
  11. *指定允许图片最大的高度
  12. *@paramdecodeConfig
  13. *指定图片的颜色属性,Bitmap.Config下的几个常量.
  14. *@paramerrorListener
  15. */
  16. privatevoidgetImageRequest(finalImageViewiv,Stringurl){
  17. ImageRequestimReq=newImageRequest(url,newListener<Bitmap>(){
  18. @Override
  19. publicvoidonResponse(Bitmaparg0){
  20. iv.setImageBitmap(arg0);
  21. }
  22. },60,60,Bitmap.Config.ARGB_8888,newStrErrListener());
  23. startVolley(imReq);
  24. }
看到现在大家肯定会疑惑写了这么多不同类型的Request到底如何运行?接下请看:

[java] view plain copy
  1. //添加及开始请求
  2. privatevoidstartVolley(Requestreq){
  3. //设置超时时间
  4. //req.setRetryPolicy(newDefaultRetryPolicy(20*1000,1,1.0f));
  5. //将请求加入队列
  6. mQueue.add(req);
  7. //开始发起请求
  8. mQueue.start();
  9. }

volley不仅提供了这些请求的方式,还提供了加载图片的一些方法和控件:

比如我们一个列表需要加载很多图片我们可以使用volley给我们提供的ImageLoader(ImageLoader比ImageRequest更加高效,因为它不仅对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。

[java] view plain copy
  1. publicclassImageAdapterextendsArrayAdapter<String>{
  2. privateRequestQueuemQueue;
  3. privateImageLoadermImageLoader;
  4. publicImageAdapter(Contextcontext,List<String>objects){
  5. super(context,0,objects);
  6. mQueue=Volley.newRequestQueue(getContext());
  7. mImageLoader=newImageLoader(mQueue,newBitmapCache());
  8. }
  9. @Override
  10. publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
  11. Stringurl=getItem(position);
  12. ImageViewimageView;
  13. if(convertView==null){
  14. imageView=newImageView(getContext());
  15. }else{
  16. imageView=(ImageView)convertView;
  17. }
  18. //getImageListener(imageView控件对象,默认图片地址,失败图片地址);
  19. ImageListenerlistener=ImageLoader.getImageListener(imageView,android.R.drawable.ic_menu_rotate,android.R.drawable.ic_delete);
  20. //get(图片地址,listener,宽,高);自动帮你处理图片的宽高再也不怕大图片的oom了
  21. mImageLoader.get(url,listener,100,200);
  22. returnimageView;
  23. }
  24. }
当然还需要重写 ImageCache这个类 //使用LruCache再也不用怕加载多张图片oom了

[java] view plain copy
  1. publicclass<spanstyle="font-family:Arial;">BitmapCache</span><spanstyle="font-family:Arial;">extendsLruCache<String,Bitmap>implementsImageCache{</span>
  2. //LruCache原理:Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。当cache已满的时候加入新的item时,在队列尾部的item会被回收。
  3. //解释:当超出指定内存值则移除最近最少用的图片内存
  4. publicstaticintgetDefaultLruCacheSize(){
  5. //拿到最大内存
  6. finalintmaxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);
  7. //拿到内存的八分之一来做图片内存缓存
  8. finalintcacheSize=maxMemory/8;
  9. returncacheSize;
  10. }
  11. publicBitmapLruCache(){
  12. this(getDefaultLruCacheSize());
  13. }
  14. publicBitmapLruCache(intsizeInKiloBytes){
  15. super(sizeInKiloBytes);
  16. }
  17. @Override
  18. protectedintsizeOf(Stringkey,Bitmapvalue){
  19. returnvalue.getRowBytes()*value.getHeight()/1024;
  20. }
  21. @Override
  22. publicBitmapgetBitmap(Stringurl){
  23. returnget(url);
  24. }
  25. @Override
  26. publicvoidputBitmap(Stringurl,Bitmapbitmap){
  27. put(url,bitmap);
  28. }
  29. }

Volley还提供的加载图片的控件 com.android.volley.NetworkImageView。(这个控件在被从父控件detach的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题,而且NetworkImageView还会根据你对图片设置的width和heigh自动压缩该图片不会产生多的内存,还有NetworkImageView在列表中使用不会图片错误

[html] view plain copy
  1. <com.android.volley.toolbox.NetworkImageView
  2. android:id="@+id/network_image_view"
  3. android:layout_width="100dp"
  4. android:layout_height="100dp"/>
使用方法:

[java] view plain copy
  1. privatevoidnetworkImageViewUse(NetworkImageViewiv,Stringurl){
  2. ImageLoaderimLoader=newImageLoader(mQueue,newBitmapLruCache());
  3. iv.setDefaultImageResId(R.drawable.ic_launcher);
  4. iv.setErrorImageResId(R.drawable.ic_launcher);
  5. iv.setImageUrl(url,imLoader);
  6. }

我们说了这么多都是请求,那么如何取消请求呢?

1.activity自动销毁时它会自定取消所有请求。

2.给请求设置标签:

[java] view plain copy
  1. request.setTag("MyTag");

取消所有指定标记的请求:

[java] view plain copy
  1. request.cancelAll("MyTag");
Volley的架构设计:



其中蓝色部分代表主线程,绿色部分代表缓存线程,橙色部分代表网络线程。我们在主线程中调用RequestQueue的add()方法来添加一条网络请求,这条请求会先被加入到缓存队列当中,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程。如果在缓存中没有找到结果,则将这条请求加入到网络请求队列中,然后处理发送HTTP请求,解析响应结果,写入缓存,并回调主线程。


接下来我们要看看如何把volley使用到实战项目里面,我们先考虑下一些问题:

从上一篇来看mQueue 只需要一个对象即可,new RequestQueue对象对资源一种浪费,我们应该在application,以及可以把取消请求的方法也在application进行统一管理,看以下代码:

[java] view plain copy
  1. packagecom.chronocloud.lib.base;
  2. importandroid.app.Application;
  3. importandroid.text.TextUtils;
  4. importcom.android.volley.Request;
  5. importcom.android.volley.RequestQueue;
  6. importcom.android.volley.VolleyLog;
  7. importcom.android.volley.toolbox.Volley;
  8. publicclassApplicationControllerextendsApplication{
  9. /**
  10. *LogorrequestTAG
  11. */
  12. publicstaticfinalStringTAG="VolleyPatterns";
  13. /**
  14. *GlobalrequestqueueforVolley
  15. */
  16. privateRequestQueuemRequestQueue;
  17. /**
  18. *Asingletoninstanceoftheapplicationclassforeasyaccessinother
  19. *places
  20. */
  21. privatestaticApplicationControllersInstance;
  22. @Override
  23. publicvoidonCreate(){
  24. super.onCreate();
  25. //initializethesingleton
  26. sInstance=this;
  27. }
  28. /**
  29. *@returnApplicationControllersingletoninstance
  30. */
  31. publicstaticsynchronizedApplicationControllergetInstance(){
  32. returnsInstance;
  33. }
  34. /**
  35. *@returnTheVolleyRequestqueue,thequeuewillbecreatedifitisnull
  36. */
  37. publicRequestQueuegetRequestQueue(){
  38. //lazyinitializetherequestqueue,thequeueinstancewillbe
  39. //createdwhenitisaccessedforthefirsttime
  40. if(mRequestQueue==null){
  41. //1
  42. //2
  43. synchronized(ApplicationController.class){
  44. if(mRequestQueue==null){
  45. mRequestQueue=Volley
  46. .newRequestQueue(getApplicationContext());
  47. }
  48. }
  49. }
  50. returnmRequestQueue;
  51. }
  52. /**
  53. *Addsthespecifiedrequesttotheglobalqueue,iftagisspecifiedthen
  54. *itisusedelseDefaultTAGisused.
  55. *
  56. *@paramreq
  57. *@paramtag
  58. */
  59. public<T>voidaddToRequestQueue(Request<T>req,Stringtag){
  60. //setthedefaulttagiftagisempty
  61. req.setTag(TextUtils.isEmpty(tag)?TAG:tag);
  62. VolleyLog.d("Addingrequesttoqueue:%s",req.getUrl());
  63. getRequestQueue().add(req);
  64. }
  65. /**
  66. *AddsthespecifiedrequesttotheglobalqueueusingtheDefaultTAG.
  67. *
  68. *@paramreq
  69. *@paramtag
  70. */
  71. public<T>voidaddToRequestQueue(Request<T>req){
  72. //setthedefaulttagiftagisempty
  73. req.setTag(TAG);
  74. getRequestQueue().add(req);
  75. }
  76. /**
  77. *CancelsallpendingrequestsbythespecifiedTAG,itisimportantto
  78. *specifyaTAGsothatthepending/ongoingrequestscanbecancelled.
  79. *
  80. *@paramtag
  81. */
  82. publicvoidcancelPendingRequests(Objecttag){
  83. if(mRequestQueue!=null){
  84. mRequestQueue.cancelAll(tag);
  85. }
  86. }
  87. }
接下来 就是Volley虽然给我们提供了很多不同的Request(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest),但是还是满足不了我们实战中的需求,我们实战开发中经常用到的是xml格式,Gson解析。

接下来我们来看看,如何自定义Request

XmlRequest:

[java] view plain copy
  1. publicclassXMLRequestextendsRequest<XmlPullParser>{
  2. privatefinalListener<XmlPullParser>mListener;
  3. publicXMLRequest(intmethod,Stringurl,Listener<XmlPullParser>listener,
  4. ErrorListenererrorListener){
  5. super(method,url,errorListener);
  6. mListener=listener;
  7. }
  8. publicXMLRequest(Stringurl,Listener<XmlPullParser>listener,ErrorListenererrorListener){
  9. this(Method.GET,url,listener,errorListener);
  10. }
  11. @Override
  12. protectedResponse<XmlPullParser>parseNetworkResponse(NetworkResponseresponse){
  13. try{
  14. StringxmlString=newString(response.data,
  15. HttpHeaderParser.parseCharset(response.headers));
  16. XmlPullParserFactoryfactory=XmlPullParserFactory.newInstance();
  17. XmlPullParserxmlPullParser=factory.newPullParser();
  18. xmlPullParser.setInput(newStringReader(xmlString));
  19. returnResponse.success(xmlPullParser,HttpHeaderParser.parseCacheHeaders(response));
  20. }catch(UnsupportedEncodingExceptione){
  21. returnResponse.error(newParseError(e));
  22. }catch(XmlPullParserExceptione){
  23. returnResponse.error(newParseError(e));
  24. }
  25. }
  26. @Override
  27. protectedvoiddeliverResponse(XmlPullParserresponse){
  28. mListener.onResponse(response);
  29. }
  30. }

GsonRequest(注意需要自行导入gson.jar):

[java] view plain copy
  1. publicclassGsonRequest<T>extendsRequest<T>{
  2. privatefinalListener<T>mListener;
  3. privateGsonmGson;
  4. privateClass<T>mClass;
  5. publicGsonRequest(intmethod,Stringurl,Class<T>clazz,Listener<T>listener,
  6. ErrorListenererrorListener){
  7. super(method,url,errorListener);
  8. mGson=newGson();
  9. mClass=clazz;
  10. mListener=listener;
  11. }
  12. publicGsonRequest(Stringurl,Class<T>clazz,Listener<T>listener,
  13. ErrorListenererrorListener){
  14. this(Method.GET,url,clazz,listener,errorListener);
  15. }
  16. @Override
  17. protectedResponse<T>parseNetworkResponse(NetworkResponseresponse){
  18. try{
  19. StringjsonString=newString(response.data,
  20. HttpHeaderParser.parseCharset(response.headers));
  21. returnResponse.success(mGson.fromJson(jsonString,mClass),
  22. HttpHeaderParser.parseCacheHeaders(response));
  23. }catch(UnsupportedEncodingExceptione){
  24. returnResponse.error(newParseError(e));
  25. }
  26. }
  27. @Override
  28. protectedvoiddeliverResponse(Tresponse){
  29. mListener.onResponse(response);
  30. }
  31. }
接下只差最后一步了就是封装它的错误处理,使用过volley的都知道,volley的监听错误提示都是NoConnectionError。。。等等,这类的错误提示,显然这不是我们想给用户呈现的错误提示,因为就算提示了用户也不明白什么意思,所以我们还要封装一下,能让用户看的更清楚的理解这些错误提示。ym—— Android网络框架Volley(体验篇)我们讲过每个请求都需要设置一个失败的监听:

[java] view plain copy
  1. //共用失败回调
  2. privateclassStrErrListenerimplementsErrorListener{
  3. @Override
  4. publicvoidonErrorResponse(VolleyErrorarg0){
  5. Toast.makeText(mContext,
  6. VolleyErrorHelper.getMessage(arg0,mContext),
  7. Toast.LENGTH_LONG).show();
  8. }
  9. }
以上代码有个VolleyError对象,我们可以从这个对象上下手:

[java] view plain copy
  1. packagecom.example.volley;
  2. importjava.util.HashMap;
  3. importjava.util.Map;
  4. importandroid.content.Context;
  5. importcom.android.volley.AuthFailureError;
  6. importcom.android.volley.NetworkError;
  7. importcom.android.volley.NetworkResponse;
  8. importcom.android.volley.NoConnectionError;
  9. importcom.android.volley.ServerError;
  10. importcom.android.volley.TimeoutError;
  11. importcom.android.volley.VolleyError;
  12. importcom.google.gson.Gson;
  13. importcom.google.gson.reflect.TypeToken;
  14. //正如前面代码看到的,在创建一个请求时,需要添加一个错误监听onErrorResponse。如果请求发生异常,会返回一个VolleyError实例。
  15. //以下是Volley的异常列表:
  16. //AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。
  17. //NetworkError:Socket关闭,服务器宕机,DNS错误都会产生这个错误。
  18. //NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。
  19. //ParseError:在使用JsonObjectRequest或JsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。
  20. //SERVERERROR:服务器的响应的一个错误,最有可能的4xx或5xxHTTP状态代码。
  21. //TimeoutError:Socket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy。
  22. publicclassVolleyErrorHelper{
  23. /**
  24. *Returnsappropriatemessagewhichistobedisplayedtotheuseragainst
  25. *thespecifiederrorobject.
  26. *
  27. *@paramerror
  28. *@paramcontext
  29. *@return
  30. */
  31. publicstaticStringgetMessage(Objecterror,Contextcontext){
  32. if(errorinstanceofTimeoutError){
  33. returncontext.getResources().getString(
  34. R.string.generic_server_down);
  35. }elseif(isServerProblem(error)){
  36. returnhandleServerError(error,context);
  37. }elseif(isNetworkProblem(error)){
  38. returncontext.getResources().getString(R.string.no_internet);
  39. }
  40. returncontext.getResources().getString(R.string.generic_error);
  41. }
  42. /**
  43. *Determineswhethertheerrorisrelatedtonetwork
  44. *
  45. *@paramerror
  46. *@return
  47. */
  48. privatestaticbooleanisNetworkProblem(Objecterror){
  49. return(errorinstanceofNetworkError)
  50. ||(errorinstanceofNoConnectionError);
  51. }
  52. /**
  53. *Determineswhethertheerrorisrelatedtoserver
  54. *
  55. *@paramerror
  56. *@return
  57. */
  58. privatestaticbooleanisServerProblem(Objecterror){
  59. return(errorinstanceofServerError)
  60. ||(errorinstanceofAuthFailureError);
  61. }
  62. /**
  63. *Handlestheservererror,triestodeterminewhethertoshowastock
  64. *messageortoshowamessageretrievedfromtheserver.
  65. *
  66. *@paramerr
  67. *@paramcontext
  68. *@return
  69. */
  70. privatestaticStringhandleServerError(Objecterr,Contextcontext){
  71. VolleyErrorerror=(VolleyError)err;
  72. NetworkResponseresponse=error.networkResponse;
  73. if(response!=null){
  74. switch(response.statusCode){
  75. case404:
  76. case422:
  77. case401:
  78. try{
  79. //servermightreturnerrorlikethis{"error":
  80. //"Someerroroccured"}
  81. //Use"Gson"toparsetheresult
  82. HashMap<String,String>result=newGson().fromJson(
  83. newString(response.data),
  84. newTypeToken<Map<String,String>>(){
  85. }.getType());
  86. if(result!=null&&result.containsKey("error")){
  87. returnresult.get("error");
  88. }
  89. }catch(Exceptione){
  90. e.printStackTrace();
  91. }
  92. //invalidrequest
  93. returnerror.getMessage();
  94. default:
  95. returncontext.getResources().getString(
  96. R.string.generic_server_down);
  97. }
  98. }
  99. returncontext.getResources().getString(R.string.generic_error);
  100. }
  101. }

以上代码中引用的xml是:

[html] view plain copy
  1. <stringname="no_internet">无网络连接~!</string>
  2. <stringname="generic_server_down">连接服务器失败~!</string>
  3. <stringname="generic_error">网络异常,请稍后再试~!</string>
接下来,数据请求这一块已经说完了,我们来说下图片这一块,我个人喜欢使用 universal-image-loader而不是volley自己提供的(个人认为使用起来 universal-image-loader更便捷一些 )。


下面主要是讲Volley在某些细节方面的选择和实现.值得我们学习的地方以及如果更好的使用Volley。


1.Volley本地缓存为什么有时候不会进行缓存?

缓存使用前提服务器必须支持,缓存,配置Cache-Control头信息,

因为Volley需要从这些头信息判断缓存是否已经过期。如果已经过期Volley将会重新从网络获取数据。

本人用抓包工具抓了无法缓存的返回头信息

可以支持缓存的头信息


2.如果我们自己写一个网络请求框架,我们内部实现会选择使用HttpURLConnection还是HttpClient?

我们通过源码来看看Volley是如何选择使用的

[java] view plain copy
  1. publicstaticRequestQueuenewRequestQueue(Contextcontext,HttpStackstack){
  2. FilecacheDir=newFile(context.getCacheDir(),DEFAULT_CACHE_DIR);
  3. StringuserAgent="volley/0";
  4. try{
  5. StringpackageName=context.getPackageName();
  6. PackageInfoinfo=context.getPackageManager().getPackageInfo(packageName,0);
  7. userAgent=packageName+"/"+info.versionCode;
  8. }catch(NameNotFoundExceptione){
  9. }
  10. if(stack==null){
  11. if(Build.VERSION.SDK_INT>=9){
  12. stack=newHurlStack();
  13. }else{
  14. stack=newHttpClientStack(AndroidHttpClient.newInstance(userAgent));
  15. }
  16. }
  17. Networknetwork=newBasicNetwork(stack);
  18. RequestQueuequeue=newRequestQueue(newDiskBasedCache(cacheDir),network);
  19. queue.start();
  20. returnqueue;
  21. }
这里会判断如果手机系统版本号是大于9(Android 2.3)的,则创建一个HurlStack的实例,否则就创建一个HttpClientStack的实例。实际上HurlStack的内部就是使用HttpURLConnection进行网络通讯的,而HttpClientStack的内部则是使用HttpClient进行网络通讯的,这里为什么这样选择呢?参考文章:Android访问网络,使用HttpURLConnection还是HttpClient?这就是它为何这么快的原因。

从这点我们可以学习到,要针对不同SDK版本做去相应更优的处理方式,这样才能达到最好的效果。


3.Volley给我们提供了ImageRrequest,ImageLoader,NetworkImageView,它们分别使用于什么场景为什么?

单张图片的加载可以通过发起 ImageReuqst 请求来实现,但为了应用内存缓存,推荐使用ImageLoader

NetwoekImageView专门用于批量图片加载的场景:

[java] view plain copy
  1. publicclassNetworkImageViewextendsImageView{
  2. privateStringmUrl;
  3. //默认显示的图片
  4. privateintmDefaultImageId;
  5. //加载失败时显示的图片
  6. privateintmErrorImageId;
  7. //主方法入口
  8. publicvoidsetImageUrl(Stringurl,ImageLoaderimageLoader){
  9. mUrl=url;
  10. mImageLoader=imageLoader;
  11. //这个方法将会对ImageView的尺寸是否有效、是否为同一张图片进行判断
  12. //在执行新请求前,也会取消上一次在这个View里启动的另一个已经失效的请求
  13. //由于篇幅的限制以及代码行数太多,这里不贴出具体实现的代码
  14. loadImageIfNecessary(false);
  15. }
  16. //如果图片已经滑离屏幕,变为不可见,将执行取消请求的操作
  17. @Override
  18. protectedvoidonDetachedFromWindow(){
  19. if(mImageContainer!=null)mImageContainer.cancelRequest();
  20. super.onDetachedFromWindow();
  21. }
  22. }
在ListView加载多张图片的时候,NetworkImageView可以防止出现图片错误的现象,以及当 NetworkImageView滑出屏幕的时候 会取消加载图片请求,这样就保证加载多张图片的时候用户快速滑动列表的流畅性。给用户带来更优的体验。

更多相关文章

  1. Android(安卓)Volloy 网络请求框架图
  2. Android调用系统分享功能总结
  3. 【Android】ListView RecyclerView
  4. Android图形图画学习(5)——解码图片
  5. Android(安卓)ImageView.ScaleType设置图解
  6. android 在你的UI中显示Bitmap - 开发文档翻译
  7. android-image-slide-panel图片照片墙的加载和滑动特效
  8. Android多点触控实现图片自由缩放
  9. Android不能进行http请求,https无法抓包的解决

随机推荐

  1. 实时Android语音对讲系统架构
  2. Android(安卓)模块化编程之引用本地的aar
  3. Android(安卓)Drawable系列(1):自定义背景以
  4. android – 多屏幕适配相关
  5. Android数据绑定Data Binding初体验
  6. Android源码阅读分析:ActivityManagerServ
  7. Android(安卓)Studio部署apk到手机后手机
  8. Android不同分辨率适配
  9. Android界面与交互设计原则(Android(安卓)
  10. Android(安卓)软键盘弹出时布局位置改变