volley框架的基本使用
使用的原因
Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目的代码中我们都能看到这两个类的身影,使用率非常高。
不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码
主要就是进行了以下三步操作:
- 创建一个RequestQueue对象。
- 创建一个XXXXXRequest对象。
- 将XXXXXXRequest对象添加到RequestQueue里面。
字符串的请求
第一步获取到RequestQuene对象
RequestQueue mQueue = Volley.newRequestQueue(context);
关于RequestQuene
RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
第二步创建StringRequest对象
第一个参数是url地址,第二个参数是请求成功处理返回来的数据 第三个参数是请求失败进行的处理
StringRequest stringRequest = 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);
}
});
第三步需要将stringRequest添加到mQuene里面即可
mQueue.add(stringRequest);
JsonObjectRequest请求
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html", 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);
}
});
其中response.toString()
就是返回来的数据只需要处理器就行
ImageRequest请求
ImageRequest request = new ImageRequest("http://www.2cto.com/uploadfile/Collfiles/20141103/201411030837265.png", new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
image.setImageBitmap(bitmap);
}
},0,0, ImageView.ScaleType.MATRIX,Bitmap.Config.ARGB_8888,new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError volleyError) {
image.setImageResource(R.drawable.ic_empty);
}
});
- 第一个参数就是图片的URL地址,这个没什么需要解释的。
- 第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中。
- 第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩, 指定成0的话就表示不管图片有多大,都不会进行压缩。
- 第五个参数用于 根据容器的边界来选择图片的缩放比例
- 第六个参数用于指定图片的颜色属性,
- 第七个参数是图片请求失败的回调 这里可以默认一张失败的图片
ImageLoader
ImageLoader也可以用于加载网络上的图片,并且它的内部也是使用ImageRequest来实现的,不过ImageLoader明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
由于ImageLoader已经不是继承自Request的了,所以它的用法也和我们之前学到的内容有所不同
总结起来大致可以分为以下四步:
- 创建一个RequestQueue对象。
- 创建一个ImageLoader对象。
- 获取一个ImageListener对象。
调用ImageLoader的get()方法加载网络上的图片。
ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() { @Override public void putBitmap(String url, Bitmap bitmap) { } @Override public Bitmap getBitmap(String url) { return null; } });
ImageLoader的构造函数接收两个参数,第一个参数就是RequestQueue对象,第二个参数是一个ImageCache对象
接下里创建ImageListen对象
ImageListener listener = ImageLoader.getImageListener(imageView,
R.drawable.default_image, R.drawable.failed_image);
最后,调用ImageLoader的get()方法来加载图片
imageLoader.get("https://img-my.youkuaiyun.com/uploads/201404/13/1397393290_5765.jpeg", listener);
可以控制其大小
imageLoader.get(“https://img-my.youkuaiyun.com/uploads/201404/13/1397393290_5765.jpeg“,
listener, 200, 200);
想要写一个好的ImageCache对象 需要用到Android的LruCache功能了
public class BitmapCache implements ImageCache {
private LruCache<String, Bitmap> mCache;
public BitmapCache() {
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);
}
}
这里我们将缓存图片的大小设置为10M。接着修改创建ImageLoader实例的代码,第二个参数传入BitmapCache的实例,如下所示:
ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());
NetworkImageView的用法
需要遵循以下五步:
- 创建一个RequestQueue对象。
- 创建一个ImageLoader对象。
- 在布局文件中添加一个NetworkImageView控件。
- 在代码中获取该控件的实例。
- 设置要加载的图片地址。
第一第二步
RequestQueue requestQueue = VolleyUtil.getQueue(getActivity());
ImageLoader loader = new ImageLoader(requestQueue,new LruImageCache());
首先修改布局文件中的代码,在里面加入NetworkImageView控件,如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Request" />
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/network_image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
/>
</LinearLayout>
然后获取控件
networkImageView = (NetworkImageView) findViewById(R.id.network_image_view);
到了NetworkImageView控件的实例之后,我们可以调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载中显示的图片,加载失败时显示的图片,以及目标图片的URL地址,如下所示:
networkImageView.setDefaultImageResId(R.drawable.default_image);
networkImageView.setErrorImageResId(R.drawable.failed_image);
networkImageView.setImageUrl("http://www.2cto.com/uploadfile/Collfiles/20141103/201411030837265.png",
imageLoader);
NetworkImageView并不需要提供任何设置最大宽高的方法也能够对加载的图片进行压缩。这是由于NetworkImageView是一个控件,在加载图片的时候它会自动获取自身的宽高,然后对比网络图片的宽度,再决定是否需要对图片进行压缩 即可以说有wrap_content
match_content
和 自定义高度宽度
定制自定义的Request
可以说真的无从下手 不如我们先看一下birdersRequest的实现方法
例如StringRequest
public class StringRequest extends Request<String> {
private Listener<String> mListener;
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
}
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(0, url, listener, errorListener);
}
protected void onFinish() {
super.onFinish();
this.mListener = null;
}
protected void deliverResponse(String response) {
if(this.mListener != null) {
this.mListener.onResponse(response);
}
}
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}
首先StringRequest是继承自Request类的,Request可以指定一个泛型类,这里指定的当然就是String了,接下来StringRequest中提供了两个有参的构造函数,参数包括请求类型,请求地址,以及响应回调等,由于我们已经很熟悉StringRequest的用法了,相信这几个参数的作用都不用再解释了吧。但需要注意的是,在构造函数中一定要调用super()方法将这几个参数传给父类,因为HTTP的请求和响应都是在父类中自动处理的。另外,由于Request类中的deliverResponse()和parseNetworkResponse()是两个抽象方法,因此StringRequest中需要对这两个方法进行实现。deliverResponse()方法中的实现很简单,仅仅是调用了mListener中的onResponse()方法,并将response内容传入即可,这样就可以将服务器响应的数据进行回调了。parseNetworkResponse()方法中则应该对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponse的data变量中的,这里将数据取出然后组装成一个String,并传入Response的success()方法中即可。
自定义xmlRequest
public class XmlRequest extends Request<XmlPullParser> {
private final Response.Listener<XmlPullParser> mListener;
public XmlRequest(int method, String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
public XmlRequest(String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
// parseNetworkResponse()方法中则应该对服务器响应的数据进行解析,
// 其中数据是以字节的形式存放在NetworkResponse的data变量中的,
// 这里将数据取出然后组装成一个String,并传入Response的success()方法中即可
@Override
protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
try {
String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
/**
* Set the input source for parser to the given reader and
* resets the parser. The event type is set to the initial value
* START_DOCUMENT.
* Setting the reader to null will just stop parsing and
* reset parser state,
* allowing the parser to free internal resources
* such as parsing buffers.
*/
// 为了给予阅读器,设置输入源给分析器。 和 重新设置 分析器 。事件类型会给一个初始值 START_DOCUMENT 开始文档
// 设置的阅读器如果为空会停止分析并且重新设置 分析器的状态 允许分析器来解析释放的内部资源 例如解析缓冲区
xmlPullParser.setInput(new StringReader(xmlString));
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));
}
}
@Override
protected void deliverResponse(XmlPullParser response) {
mListener.onResponse(response);
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
// self-defined user agent
Map<String, String> headerMap = new HashMap<String, String>();
headerMap.put("User-Agent", "android-open-project-analysis/1.0");
return headerMap;
}
}
然后我们就可以像上面的一样进行xml的请求
// 发起请求
XmlRequest request = new XmlRequest(StringUtil.preUrl(Constants.DEFAULT_XML_REQUEST_URL),
new Response.Listener<XmlPullParser>() {
@Override
public void onResponse(XmlPullParser parser) {
try {
weatherDataList.clear();
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
String nodeName = parser.getName();
if ("city".equals(nodeName)) {
Map<String, String> weatherMap = new HashMap<String, String>();
weatherMap.put("city", parser.getAttributeValue(2));
weatherMap.put("detail", parser.getAttributeValue(5));
weatherMap.put("temp", parser.getAttributeValue(7)+"℃ 到 "+parser.getAttributeValue(6)+"℃");
weatherMap.put("wind", parser.getAttributeValue(8));
weatherDataList.add(weatherMap);
}
break;
}
eventType = parser.next();
}
adapter.notifyDataSetChanged();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
ToastUtil.showToast(getActivity(), getResources().getString(R.string.request_fail_text));
}
});
自定义gsonRequest
public class GsonRequest<T> extends Request<T> {
private final Response.Listener<T> mlisten;
private Gson gson;
private Class<T> mClass;
public GsonRequest(int method, String url,Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mClass = clazz;
gson = new Gson();
mlisten = listener;
}
public GsonRequest(String url, Class<T> clazz,Response.Listener<T> listener, Response.ErrorListener errorListener) {
this(Method.GET, url,clazz,listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse networkResponse) {
try {
String jsonString = new String(networkResponse.data,
HttpHeaderParser.parseCharset(networkResponse.headers));
return Response.success(gson.fromJson(jsonString,mClass),
HttpHeaderParser.parseCacheHeaders(networkResponse));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T t) {
mlisten.onResponse(t);
}
}
JSON格式数据
{“weatherinfo”:{“city”:”北京”,”cityid”:”101010100”,”temp”:”19”,”WD”:”南风”,”WS”:”2级”,”SD”:”43%”,”WSE”:”2”,”time”:”19:45”,”isRadar”:”1”,”Radar”:”JC_RADAR_AZ9010_JB”}}
需要创建
public class WeatherInfo {
private String city;
private String temp;
private String time;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
另一个类
public class Weather {
private WeatherInfo weatherinfo;
public WeatherInfo getWeatherinfo() {
return weatherinfo;
}
public void setWeatherinfo(WeatherInfo weatherinfo) {
this.weatherinfo = weatherinfo;
}
}
然后像上面一样进行请求
RequestQueue quene = VolleyUtil.getQueue(this);
GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(
"http://www.weather.com.cn/adat/sk/101010100.html", Weather.class,
new Response.Listener<Weather>() {
@Override
public void onResponse(Weather weather) {
WeatherInfo WeatherInfo = weather.getWeatherinfo();
Log.d("TAG", "city is " + WeatherInfo.getCity());
Log.d("TAG", "temp is " + WeatherInfo.getTemp());
Log.d("TAG", "time is " + WeatherInfo.getTime());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
quene.add(gsonRequest);
参考的文章
http://blog.youkuaiyun.com/guolin_blog/article/details/17482095
http://blog.youkuaiyun.com/guolin_blog/article/details/17482165