Volley是google官方推出的一个开源网络访问库,在项目中直接使用它,而不须要写一大堆的重复的代码;html
项目主页:android
https://android.googlesource.com/platform/frameworks/volleyjson
Volley中一个重要的类就是RequestQueue,不用多说,只看命名就知道它是一个请求队列,用于存放咱们添加进去的网络请求;缓存
咱们能够经过Volley.newRequestQueue(Context context);获取一个RequestQueue对象,一般一个应用程序中使用一个RequestQueue实例便可,所以能够把RequestQueue实例存放在Application中,当作一个全局变量;网络
下面直接经过例子来学习此开源库的使用;app
1、字符串请求ide
protected void stringRequest() { String url = "http://www.baidu.com"; StringRequest sr = new StringRequest(Method.GET, url, new Listener<String>() { @Override public void onResponse(String response) { Log.e(tag, "" + response); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); sr.setTag("tag"); reqQueue.add(sr); }
其中reqQueue即为RequestQueue实例对象(同下文);
咱们只须要产生一个StringRequest实例,而后添加进RequestQueue队列当中便可,在建立实例的时候,会分别设置请求成功和请求失败时的监听回调,在监听器里面咱们能够作相应的处理;函数
2、Json请求学习
Json请求分别两种,分别是JsonObjectRequest和JsonArrayRequest,下边咱们来看一个JsonObjectRequest请求;fetch
protected void jsonObjectRequest() { String url = "http://m.weather.com.cn/data/101010100.html"; JsonObjectRequest jor = new JsonObjectRequest(Request.Method.GET, url, null, new Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { Log.e(tag, "" + response); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); jor.setTag("tag"); reqQueue.add(jor); }
和StringRequest相仿,再也不表述,同理JsonArrayRequest也是同样;
3、图片请求
protected void imageRequest() { iv = (ImageView) findViewById(R.id.iv); String url = "http://img0.bdstatic.com/img/image/shouye/hjxnzz04.jpg"; ImageRequest ir = new ImageRequest(url, new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { iv.setImageBitmap(response); } }, 0, 0, Config.RGB_565, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { iv.setImageResource(R.drawable.ic_launcher); } }); ir.setTag("tag"); reqQueue.add(ir); // ImageRequest的构造函数接收六个参数 // url:图片的URL地址 // listener:图片请求成功的回调 // maxWidth:容许图片最大的宽度,指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示无论图片有多大,都不会进行压缩. // maxHeight:容许图片最大的高度 // decodeConfig:图片的颜色属性 // errorListener:图片请求失败的回调 }
ImageRequest和StringRequest差很少,不过能够经过设置maxWidth和maxHeight对图片进行压缩;
在上面这个请求中,咱们只把请求回来的图片直接设置给了ImageView,并无作其它处理,是否有点不严谨,内存溢出了咋办?请看下面!
4、ImageLoader
protected void imageLoader() { iv = (ImageView) findViewById(R.id.iv); String url = "http://img0.bdstatic.com/img/image/shouye/hjxnzz04.jpg"; ImageLoader loader = new ImageLoader(reqQueue, new BitmapCache()); ImageListener listener = new ImageListener() { @Override public void onErrorResponse(VolleyError error) { } @Override public void onResponse(ImageContainer response, boolean isImmediate) { } }; // listener = ImageLoader.getImageListener(iv, R.drawable.ic_launcher, // R.drawable.ic_launcher); loader.get(url, listener, 0, 0); // ImageLoader明显要比ImageRequest更加高效,它不只能够帮咱们对图片进行缓存,还能够过滤掉重复的连接,避免重复发送请求. // 它的内部也是使用ImageRequest来实现的; }
ImageLoader功能就要强大一些,它能够对图片进行缓存,其实它内部仍是经过ImageRequest来实现的;经过ImageLoader.get(url,listener,maxWidth,maxHeight)自动获取图片;若是须要详细的监听图片的获取过程,则new一个ImageListener实例,若是不须要,则经过ImageLoader.getImageListener(int defaultResouceId,int errorResourceId);来设置默认的图片和请求失败时的图片;
在建立ImageLoader实例的时候,须要一个ImageCache对象,我在这里简单自定义了一个ImageCache对象用于缓存图片;
public class BitmapCache implements ImageCache { public static int getDefaultLruCacheSize() { final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int cacheSize = maxMemory / 8; return cacheSize; } private final String tag = "BitmapCache"; private LruCache<String, Bitmap> mCache; public BitmapCache() { int maxSize = getDefaultLruCacheSize(); 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) { Log.e(tag, "getBitmap"); return mCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { Log.e(tag, "putBitmap"); mCache.put(url, bitmap); } }
5、NetworkImageView
protected void networkImageView() { String url = "http://img0.bdstatic.com/img/image/shouye/hjxnzz04.jpg"; NetworkImageView niv = ...; niv.setErrorImageResId(R.drawable.ic_launcher); niv.setDefaultImageResId(R.drawable.ic_launcher); ImageLoader loader = new ImageLoader(reqQueue, new BitmapCache()); niv.setImageUrl(url, loader); // NetworkImageView是一个自定义控制,它是继承自ImageView的,在原生的基础之上加入了加载网络图片的功能 // 使用ImageRequest和ImageLoader这两种方式来加载网络图片,均可以传入一个最大宽度和高度的参数来对图片进行压缩, // 但NetworkImageView并不须要提供任何设置最大宽高的方法也可以对加载的图片进行压缩. // 这是因为NetworkImageView是一个控件,在加载图片的时候它会自动获取自身的宽高,而后对比网络图片的宽度,再决定是否须要对图片进行压缩. // 也就是说,压缩过程是在内部彻底自动化的,并不须要咱们关心,NetworkImageView会始终呈现给咱们一张大小刚恰好的网络图片. }
NetworkImageView继承处ImageView,它的使用更加简单,它的一些特性上面已经列出,使用的时候直接把原始的ImageView替换便可;
6、补充
上面讲了几个经常使用的类的使用,下面对一些设置进行补充记录一下;
上面的网络请求都是最基本的请求,并无带特定的参数,那么问题来了,若是我须要设定一些请求参数怎么办?请看下面!
Request在发出请求的时候,会调用两个方法getParams和getHeaders,分别读取请求时附带的参数和请求头,咱们重写这两方法,把须要设置的参数给写进去便可,下面是一个简单的例子;
StringRequest sr = new StringRequest(Method.GET, url, new Listener<String>() { @Override public void onResponse(String response) { Log.e(tag, "" + response); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("param1", "value1"); map.put("param2", "value2"); return map; } @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("Content-Type", "application/json"); return map; } };
7、管理缓存
<1>.RequestQueue默认会把数据缓存到本地,好比一张图片,一些相关方法参考DiskBasedCache类;但有时咱们不须要对数据进行缓存,只须要在添加请求的时候经过Request.setShouldCache(false)便可;
<2>.查看缓存:
RequestQueue reqQueue = ...;
Cache cache = reqQueue.getCache(); Entry entry = cache.get(url); if(entry != null){ try { String data = new String(entry.data, "UTF-8"); // handle data, like converting it to xml, json, bitmap etc., } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }else{ // Cached response doesn't exists. Make network call here }
Cache还提供了其它相关的方法,好比remove{删除},invalidate{不会删除缓存的数据,而是使其失效,当网络请求成功获取到新数据时,会覆盖掉以前的数据},clear{清空};
除了使用Cache.clear()方法清空缓存,还有另一种方法来请空缓存:
protected void clearCache() { ClearCacheRequest ccr = new ClearCacheRequest(reqQueue.getCache(), new Runnable() { @Override public void run() { } }); ccr.setTag(this); reqQueue.add(ccr); }
8、取消请求
有时候,咱们可能须要手动取消请求,好比,在一个请求还未完成时,程序即出了,若是再继续请求没有太大的意义,还有可能形成程序崩溃,一般这种状况咱们在onStop方法中取消请求,下面就来看看如何取消请求;
RequestQueue reqQueue ...;
reqQueue.cancelAll(this); // reqQueue.cancelAll(new RequestFilter() { // @Override // public boolean apply(Request<?> request) { // return false; // } // });
9、自定义Request
先来看StringRequest的源码实现
public class StringRequest extends Request<String> { private final Listener<String> mListener; /** * Creates a new request with the given method. * * @param method the request {@link Method} to use * @param url URL to fetch the string at * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } /** * Creates a new GET request. * * @param url URL to fetch the string at * @param listener Listener to receive the String response * @param errorListener Error listener, or null to ignore errors */ 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)); } }
经过上面StringRequest的源码,相信实现一个自定义Request对你们来讲都没有太大的难度,也就是重写两个方法,deliverResponse(仅仅一行代码,有什么难的?)和parseNetworkResponse,主要就是实现parseNetworkResponse,下面参照StringRequest来实现一个XmlRequest;
public class XmlRequest extends Request<XmlPullParser> { private Listener<XmlPullParser> listener; public XmlRequest(int method, String url, Listener<XmlPullParser> listener, ErrorListener errorlistener) { super(method, url, errorlistener); this.listener = listener; } public XmlRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorlistener) { this(Method.GET, url, listener, errorlistener); } @Override protected Response<XmlPullParser> parseNetworkResponse( NetworkResponse response) { try { String str = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); parser.setInput(new StringReader(str)); return Response.success(parser, HttpHeaderParser.parseCacheHeaders(response)); } catch (Exception e) { return Response.error(new ParseError()); } } @Override protected void deliverResponse(XmlPullParser response) { listener.onResponse(response); } }
10、自定义Request2(GsonRequest)
对于上面的JsonObjectRequest,咱们只是获得了JSONObject,联想Gson,咱们是否也能够直接把获取到的Json数据转换为一个实体对象呢?固然能够,并且也很是简单;
public class GsonRequest<T> extends Request<T> { private Listener<T> listener; private Gson gson; private Class<T> clazz; public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener, ErrorListener errorlistener) { super(method, url, errorlistener); this.listener = listener; this.clazz = clazz; gson = new Gson(); } 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 str = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(gson.fromJson(str, clazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { listener.onResponse(response); } }
完!
参考:http://www.androidhive.info/2014/05/android-working-with-volley-library-1/