欢迎使用CSDN-markdown编辑器

来源:互联网 发布:linux ftp登录 编辑:程序博客网 时间:2024/06/11 05:17

0. 前言  

Android系统中主要提供了HttpURLConnectionHttpClient进行网络通信,但是如果不对其进行封装就很容易就会写出重复代码。因此一些Android网络通信框架应运而生, Volley就是其中的佼佼者,Volley不仅可以进行HTTP通信,也可以轻松加载网络上的图片Volley设计的初衷就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。原因总结如下:

1Volley的网络请求线程池默认为4。因此只能并发进行4个请求(多了排队),容易被4个较大文件的下载任务阻塞其余请求

2RequestparseNetWorkResponse()方法返回byte[]类型,需要把传输到的数据读到内存中。如果文件过大,容易引发OOM

 

1.  Volley的基本使用

1.1  HTTP GET请求

首先在AS中导入Volley的jar包

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());  
  2. StringRequest stringRequest_get = new StringRequest(“http://www.baidu.com”,  
  3.        new Response.Listener<String>() {  
  4.          @Override  
  5.          public void onResponse(String response) {  
  6.                Log.d(”TAG”, response);  
  7.          }  
  8.       }, new Response.ErrorListener() {  
  9.             @Override  
  10.             public void onErrorResponse(VolleyError error) {  
  11.                 Log.e(”TAG”, error.getMessage(), error);  
  12.             }  
  13.   });  
  14. mQueue.add(stringRequest);  
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());StringRequest stringRequest_get = new StringRequest("http://www.baidu.com",       new Response.Listener<String>() {         @Override         public void onResponse(String response) {               Log.d("TAG", response);         }      }, new Response.ErrorListener() {            @Override            public void onErrorResponse(VolleyError error) {                Log.e("TAG", error.getMessage(), error);            }  });mQueue.add(stringRequest);

StringRequest的构造函数需要传入三个参数,第一个是URL地址,第二/三个参数是服务器响应成功/失败的回调。若成功则将返回的html代码转为String打印出log


1.2  HTTP POST请求

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());  
  2. StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) {    
  3.     @Override    
  4.     protected Map<String, String> getParams() throws AuthFailureError {    
  5.         Map<String, String> map = new HashMap<String, String>();    
  6.         map.put(”params1”“value1”);    
  7.         map.put(”params2”“value2”);    
  8.         return map;    
  9.     }    
  10. };    
  11. mQueue.add(stringRequest);  
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) {      @Override      protected Map<String, String> getParams() throws AuthFailureError {          Map<String, String> map = new HashMap<String, String>();          map.put("params1", "value1");          map.put("params2", "value2");          return map;      }  };  mQueue.add(stringRequest);

当发出POST请求的时候,Volley会尝试调用StringRequest的父类中的getParams()方法来获取POST参数,因此我们需要在StringRequest中重写getParams()方法,设置POST参数即可。


1.3  JsonRequest

StringRequest一样,JsonRequest也是继承自Request类的 JsonRequest是一个抽象类,有两个子类JsonObjectRequestJsonArrayRequest,前者用于请求一段JSON数据的,后者用于请求一段JSON数组。下面是使用前者进行一段Json请求的范例代码。

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. //队列初始化以及request加入队列略  
  2. JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null,    
  3.         new Response.Listener<JSONObject>() {    
  4.             @Override    
  5.             public void onResponse(JSONObject response) {    
  6.                 Log.d(”TAG”, response.toString());    
  7.             }    
  8.         }, new Response.ErrorListener() {    
  9.             @Override   
  10.             public void onErrorResponse(VolleyError error) {    
  11.                 Log.e(”TAG”, error.getMessage(), error);    
  12.             }    
  13. });    
//队列初始化以及request加入队列略JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null,          new Response.Listener<JSONObject>() {              @Override              public void onResponse(JSONObject response) {                  Log.d("TAG", response.toString());              }          }, new Response.ErrorListener() {              @Override             public void onErrorResponse(VolleyError error) {                  Log.e("TAG", error.getMessage(), error);              }  });  


1.4  ImageRequest

Volley支持对图片的加载,因为ImageRequest也是继承自Request类,因此用法也大同小异。下面直接传入图片url,返回数据后内部解析为bitmap,最后设置给ImageView。否则设置默认图片。

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. ImageRequest imageRequest = new ImageRequest(url_image,    
  2.         new Response.Listener<Bitmap>() {    
  3.             @Override    
  4.             public void onResponse(Bitmap response) {    
  5.                 imageView.setImageBitmap(response);    
  6.             }    
  7.         }, 00, Config.RGB_565, new Response.ErrorListener() {    
  8.             @Override    
  9.             public void onErrorResponse(VolleyError error) {    
  10.                 imageView.setImageResource(R.drawable.default_image);    
  11.             }    
  12. });    
ImageRequest imageRequest = new ImageRequest(url_image,          new Response.Listener<Bitmap>() {              @Override              public void onResponse(Bitmap response) {                  imageView.setImageBitmap(response);              }          }, 0, 0, Config.RGB_565, new Response.ErrorListener() {              @Override              public void onErrorResponse(VolleyError error) {                  imageView.setImageResource(R.drawable.default_image);              }  });  

需要注意的是,第三/四个参数用于指定允许图片最大的宽/,若网络图片的实际宽高大于该设定值,则会对图片进行压缩,指定成0的话就表示不进行压缩。第五个参数用于指定图片的颜色属性Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。不过这种加载图片的方式并不被推荐,因为下面有更好的。


1.5  ImageLoader

ImageLoader基于ImageRequest实现,并且更加智能,多出了帮图片缓存的功能,还可以过滤掉重复的请求链接。但是ImageLoader已经不再继承自Request类。

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. //mQueue初始化略  
  2. ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());  
  3. ImageListener listener = ImageLoader.getImageListener(imageView,  R.drawable.default_image, R.drawable.failed_image);    
  4. imageLoader.get(url_image, listener, 200200);  //限制最大宽高  
  5. public class BitmapCache implements ImageCache {   
  6.     //内部使用LRU实现   
  7.     private LruCache<String, Bitmap> mCache;    
  8. public BitmapCache() {    
  9.        //缓存图片的大小设置为10M  
  10.         int maxSize = 10 * 1024 * 1024;    
  11.         mCache = new LruCache<String, Bitmap>(maxSize) {    
  12.             @Override    
  13.             protected int sizeOf(String key, Bitmap bitmap) {    
  14.                 return bitmap.getRowBytes() * bitmap.getHeight();    
  15.             }    
  16.         };    
  17.     }    
  18.     @Override    
  19.     public Bitmap getBitmap(String url) {    
  20.         return mCache.get(url);    
  21.     }    
  22.     @Override    
  23.     public void putBitmap(String url, Bitmap bitmap) {    
  24.         mCache.put(url, bitmap);    
  25.     }    
  26. }    
//mQueue初始化略ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());ImageListener listener = ImageLoader.getImageListener(imageView,  R.drawable.default_image, R.drawable.failed_image);  imageLoader.get(url_image, listener, 200, 200);  //限制最大宽高public class BitmapCache implements ImageCache {     //内部使用LRU实现     private LruCache<String, Bitmap> mCache;  public BitmapCache() {         //缓存图片的大小设置为10M        int maxSize = 10 * 1024 * 1024;          mCache = new LruCache<String, Bitmap>(maxSize) {              @Override              protected int sizeOf(String key, Bitmap bitmap) {                  return bitmap.getRowBytes() * bitmap.getHeight();              }          };      }      @Override      public Bitmap getBitmap(String url) {          return mCache.get(url);      }      @Override      public void putBitmap(String url, Bitmap bitmap) {          mCache.put(url, bitmap);      }  }  

第二行构造一个ImageLoader对象,其中第二个参数是一个ImageCache对象,参数二为自定义的用户缓存的类BitmapCache,该类继承了ImageCache。第三行获取一个ImageListener对象,传入参数比较简单,看名字就知道了。第四行调用ImageLoaderget()方法来加载图片。

 

1.6  NetworkImageView

这是第三种加载图片的方式,相对来说也是被用的比较多的方式。NetworkImageView继承自ImageView的,在原生的基础之上加入了加载网络图片的功能。用法仍旧是先创建一个RequestQueue对象和一个ImageLoader对象。接下来是在xml中定义我们的NetworkImageView,宽高表示裁剪到此宽高,wrap_content表示不裁剪。

[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <com.android.volley.toolbox.NetworkImageView     
  2.         android:id=“@+id/network_image_view”    
  3.         android:layout_width=“100dp”    
  4.         android:layout_height=“100dp”/>    
<com.android.volley.toolbox.NetworkImageView           android:id="@+id/network_image_view"          android:layout_width="100dp"          android:layout_height="100dp"/>  

Activity中获取到NetworkImageView实例后,就可以调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载时显示的图片,加载失败时显示的图片,以及目标图片的URL地址。

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. networkImageView.setDefaultImageResId(R.drawable.default_image);    
  2. networkImageView.setErrorImageResId(R.drawable.failed_image);    
  3. networkImageView.setImageUrl(url_image,imageLoader);    
networkImageView.setDefaultImageResId(R.drawable.default_image);  networkImageView.setErrorImageResId(R.drawable.failed_image);  networkImageView.setImageUrl(url_image,imageLoader);  

2.  自定义Request

在网络上传输的数据常用到XMLJSON格式,那么如果想要请求一条XML/JSON格式的数据就需要拓展我们的Volley

 

2. 1  XMLRequest

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. public class StringRequest extends Request<String> {    
  2.     private final Listener<String> mListener;    
  3.     public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {    
  4.         super(method, url, errorListener);    
  5.         mListener = listener;    
  6.     }    
  7.     public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {    
  8.         this(Method.GET, url, listener, errorListener);    
  9.     }    
  10.     
  11.     @Override    
  12.     protected void deliverResponse(String response) {    
  13.         mListener.onResponse(response);    
  14.     }    
  15.     
  16.     @Override    
  17.     protected Response<String> parseNetworkResponse(NetworkResponse response) {    
  18.         String parsed;    
  19.         try {    
  20.             parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));    
  21.         } catch (UnsupportedEncodingException e) {    
  22.             parsed = new String(response.data);    
  23.         }    
  24.         return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    
  25.     }    
  26. }    
public class StringRequest extends Request<String> {      private final Listener<String> mListener;      public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {          super(method, url, errorListener);          mListener = listener;      }      public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {          this(Method.GET, url, listener, errorListener);      }      @Override      protected void deliverResponse(String response) {          mListener.onResponse(response);      }      @Override      protected Response<String> parseNetworkResponse(NetworkResponse response) {          String parsed;          try {              parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));          } catch (UnsupportedEncodingException e) {              parsed = new String(response.data);          }          return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));      }  }  

拓展之前先要看一下原有的Request的子类是如何实现的,上面以StringRequest为例。StringRequest中提供了两个有参的构造函数,参数包括请求类型,请求地址,以及响应回调等,在构造函数中一定要调用super()方法将这几个参数传给父类,因为HTTP的请求和响应都是在父类中处理的。

由于Request类中的deliverResponse()parseNetworkResponse()是两个抽象方法,因此StringRequest中对这两个方法进行了实现。前者调用了mListener中的onResponse()方法,并将response内容传入即完成了将服务器响应的数据进行回调。后者对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponsedata变量中(前言中在Volley为什么不适合大文件下载就讲到了),这里将数据取出然后组装成一个String,并传入Responsesuccess()方法中。

在了解了StringRequest之后,我们自定义实现我们的XMLRequest

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. public class XMLRequest extends Request<XmlPullParser> {    
  2.     private final Listener<XmlPullParser> mListener;    
  3.     public XMLRequest(int method, String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {    
  4.         super(method, url, errorListener);    
  5.         mListener = listener;    
  6.     }    
  7.     
  8.     public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {    
  9.         this(Method.GET, url, listener, errorListener);    
  10.     }    
  11.     
  12.     @Override    
  13.     protected void deliverResponse(XmlPullParser response) {    
  14.         mListener.onResponse(response);    
  15.     }    
  16.   
  17.     @Override    
  18.     protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {    
  19.         try {    
  20.           //先转为字符串  
  21.             String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));    
  22.           //重点在于解析xml  
  23.             XmlPullParserFactory factory = XmlPullParserFactory.newInstance();    
  24.             XmlPullParser xmlPullParser = factory.newPullParser();    
  25.             xmlPullParser.setInput(new StringReader(xmlString));  
  26.           //返回XmlPullParser实例  
  27.             return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));    
  28.         } catch (UnsupportedEncodingException e) {    
  29.             return Response.error(new ParseError(e));    
  30.         } catch (XmlPullParserException e) {    
  31.             return Response.error(new ParseError(e));    
  32.         }    
  33.     }      
  34. }    
  35.   
  36. //使用我们的XMLRequest  
  37. XMLRequest xmlRequest = new XMLRequest( url_xml, new Response.Listener<XmlPullParser>() {    
  38.             @Override    
  39.             public void onResponse(XmlPullParser response) {    
  40.                 try {    
  41.                     int eventType = response.getEventType();    
  42.                     while (eventType != XmlPullParser.END_DOCUMENT) {    
  43.                         switch (eventType) {    
  44.                         case XmlPullParser.START_TAG:    
  45.                             String nodeName = response.getName();    
  46.                             if (WANTED_TAG.equals(nodeName)) {    
  47.                                 String pName = response.getAttributeValue(0);    
  48.                                 Log.d(”TAG”“pName is ” + pName);    
  49.                             }    
  50.                             break;    
  51.                         }    
  52.                         eventType = response.next();    
  53.                     }    
  54.                 } catch (XmlPullParserException e) {    
  55.                     e.printStackTrace();    
  56.                 } catch (IOException e) {    
  57.                     e.printStackTrace();    
  58.                 }    
  59.             }    
  60.         }, new Response.ErrorListener() {    
  61.             @Override    
  62.             public void onErrorResponse(VolleyError error) {    
  63.                 Log.e(”TAG”, error.getMessage(), error);    
  64.             }    
  65.         });    
public class XMLRequest extends Request<XmlPullParser> {      private final Listener<XmlPullParser> mListener;      public XMLRequest(int method, String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {          super(method, url, errorListener);          mListener = listener;      }      public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {          this(Method.GET, url, listener, errorListener);      }      @Override      protected void deliverResponse(XmlPullParser response) {          mListener.onResponse(response);      }      @Override      protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {          try {            //先转为字符串            String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));            //重点在于解析xml            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();              XmlPullParser xmlPullParser = factory.newPullParser();              xmlPullParser.setInput(new StringReader(xmlString));          //返回XmlPullParser实例            return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));          } catch (UnsupportedEncodingException e) {              return Response.error(new ParseError(e));          } catch (XmlPullParserException e) {              return Response.error(new ParseError(e));          }      }    }  //使用我们的XMLRequestXMLRequest xmlRequest = new XMLRequest( url_xml, new Response.Listener<XmlPullParser>() {              @Override              public void onResponse(XmlPullParser response) {                  try {                      int eventType = response.getEventType();                      while (eventType != XmlPullParser.END_DOCUMENT) {                          switch (eventType) {                          case XmlPullParser.START_TAG:                              String nodeName = response.getName();                              if (WANTED_TAG.equals(nodeName)) {                                  String pName = response.getAttributeValue(0);                                  Log.d("TAG", "pName is " + pName);                              }                              break;                          }                          eventType = response.next();                      }                  } catch (XmlPullParserException e) {                      e.printStackTrace();                  } catch (IOException e) {                      e.printStackTrace();                  }              }          }, new Response.ErrorListener() {              @Override              public void onErrorResponse(VolleyError error) {                  Log.e("TAG", error.getMessage(), error);              }          });  

2. 2  GsonRequest

用过Gson的都知道Gson解析有多方便,这里可以把VolleyGson结合在一起吗?当然可以。重写代码基本上大同小异。前提是先导入Gson的jar包

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. public class GsonRequest<T> extends Request<T> {    
  2.     private final Listener<T> mListener;    
  3.     private Gson mGson;    
  4.     private Class<T> mClass;    
  5.     public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {    
  6.         super(method, url, errorListener);    
  7.         mGson = new Gson();    
  8.         mClass = clazz;    
  9.         mListener = listener;    
  10.     }    
  11.     
  12.     public GsonRequest(String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {    
  13.         this(Method.GET, url, clazz, listener, errorListener);    
  14.     }    
  15.     
  16.     @Override    
  17.     protected Response<T> parseNetworkResponse(NetworkResponse response) {    
  18.         try {    
  19.             String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));  
  20.           //结合Gson解析    
  21.             return Response.success(mGson.fromJson(jsonString, mClass),  HttpHeaderParser.parseCacheHeaders(response));    
  22.         } catch (UnsupportedEncodingException e) {    
  23.             return Response.error(new ParseError(e));    
  24.         }    
  25.     }    
  26.     
  27.     @Override    
  28.     protected void deliverResponse(T response) {    
  29.         mListener.onResponse(response);    
  30. }    
  31. }    
  32.   
  33. //使用我们的GsonRequest  
  34. GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(url_json,YourClass.class,    
  35.         new Response.Listener<Weather>() {    
  36.             @Override    
  37.             public void onResponse(YourClass obj) {    
  38.             //这里获得obj对应的json中的数据  
  39.             }    
  40.         }, new Response.ErrorListener() {    
  41.             @Override    
  42.             public void onErrorResponse(VolleyError error) {    
  43.                 Log.e(”TAG”, error.getMessage(), error);    
  44.             }    
  45.         });    
public class GsonRequest<T> extends Request<T> {      private final Listener<T> mListener;      private Gson mGson;      private Class<T> mClass;      public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {          super(method, url, errorListener);          mGson = new Gson();          mClass = clazz;          mListener = listener;      }      public GsonRequest(String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {          this(Method.GET, url, clazz, listener, errorListener);      }      @Override      protected Response<T> parseNetworkResponse(NetworkResponse response) {          try {              String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));          //结合Gson解析              return Response.success(mGson.fromJson(jsonString, mClass),  HttpHeaderParser.parseCacheHeaders(response));          } catch (UnsupportedEncodingException e) {              return Response.error(new ParseError(e));          }      }      @Override      protected void deliverResponse(T response) {          mListener.onResponse(response);  }  }  //使用我们的GsonRequestGsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(url_json,YourClass.class,          new Response.Listener<Weather>() {              @Override              public void onResponse(YourClass obj) {              //这里获得obj对应的json中的数据            }          }, new Response.ErrorListener() {              @Override              public void onErrorResponse(VolleyError error) {                  Log.e("TAG", error.getMessage(), error);              }          });  


0 0
原创粉丝点击