Volley
Volley简介
Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目代码中我们都能看到这两个类的身影,使用率非常高。不过HttpURLConnection和HttpClient的用法还是有些复杂,Android开发团队也是意识到有必要将HTTP通信操作在进行简化,于是在2013年Google I/O大会上退出来一个新的网络通信框架——volley。
Volley处理简单易用之外,在性能方面也进行了大幅度的调整,他的设计目标就是非常适合去进行数据量不大,但通信频繁的网络A座,而对于大数据量的网络操作,比如下载文件,Volley的表现就会非常糟糕。
在使用Volley时,需要导入框架包
jar包的下载地址是:https://code.google.com/p/google-gson/downloads/list 。
或者
Volley提供的功能
- JSON,图像等的异步下载
- 网络请求的排序(scheduling)
- 网络请求的优先级处理
- 缓存
- 多级别取消请求
- 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)
StringRequest
RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求, 然后按照-定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资
源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
发送一个字符串的请求
RequestQueue queue=null;
public void sendStringRequestClick(View view){
String url="https://www.baidu.com";
//创建一个字符串请求 参数(请求方式,URL,响应的回调接口,错误的回调接口)
StringRequest request=new StringRequest(Request.Method.GET,
url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {//正确时的回调方法
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {//错误时的回调方法
System.out.println(error);
}
});
queue.add(request);
}
注意:一开始运行时url地址是http://www.baidu.com结果回调的是VolleyError的方法,之后改成https就可以了。
发送一个带参数的POST请求
public void sendParansPostStringClick(View view){
String url = "http://apis.baidu.com/apistore/weatherservice/citylist";
StringRequest request=new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
}){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params=new HashMap<>();
params.put("cityname","朝阳");
return params;
}
};
queue.add(request);
}
JsonRequest
类似于StringRequest,JsonRequest也是继承自Request类的,JsonRequest是一个抽象类,JsonRequest有两个直接的子类JsonObjectRequest和JsonArrayRequest。
示例
public void sendJsonRequestClick(View view){
String url="http://ip.taobao.com/service/getIpInfo.php?ip=63.223.108.42&qq-pf-to=pcqq.group";
//请求参数对象为JSONObject
// JSONObject jsonObject=new JSONObject();
// try {
// jsonObject.put("param","value");
// } catch (JSONException e) {
// e.printStackTrace();
// }
//参数(请求方式,URL,请求参数,响应的回调接口,错误的回调接口)
JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
ImageRequest
发送一个ImageRequest
public void sendImageRequestClick(View view){
String url="http://b.hiphotos.baidu.com/image/pic/item/4b90f603738da977f86d8b56be51f8198618e309.jpg";
//参数(URL,响应的回调接口,指定图片的宽,指定图片的高(指定为0,不压缩),指定图片颜色属性,错误的回调接口(可以指定显示一张默认的图片))
ImageRequest request=new ImageRequest(url, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
ImageLoader
ImageLoader也可以用于加载网络图片,也是使用ImageRequest来实现的,不过ImageLoader明显比ImageRequest更加高效,因为它不仅可以对图片进行缓存,还可以过滤重复的连接,避免重复发送请求。
使用ImageLoader加载图片
新建一个ImageLoader对象
public void ImageLoaderClick(View view){
String url="http://b.hiphotos.baidu.com/image/pic/item/4b90f603738da977f86d8b56be51f8198618e309.jpg";
ImageLoader imageLoader=new ImageLoader(queue, new ImageLoader.ImageCache() {
//对图片进行缓存
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
//获取ImageListener对象
ImageLoader.ImageListener listener=ImageLoader.getImageListener(imageView,R.mipmap.ic_launcher,R.mipmap.ic_launcher_round);
imageLoader.get(url,listener,500,500);
}
实现一个带缓存的ImageCache
private class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String,Bitmap> cache;
private int maxCache=10*1024;
public BitmapCache(){
cache=new LruCache(maxCache);
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url,bitmap);
}
}
修改ImageLoaderClick方法中的一行代码
ImageLoader imageLoader=new ImageLoader(queue, new BitmapCache());
NetworkImageView
布局
<com.android.volley.toolbox.NetworkImageView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/networkImageView"
app:layout_constraintTop_toBottomOf="@id/imageView"
tools:ignore="MissingConstraints" />
通过networkImageView组件加载图片
private void networkImageView() {
networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
networkImageView.setErrorImageResId(R.mipmap.ic_launcher);
String url="http://b.hiphotos.baidu.com/image/pic/item/4b90f603738da977f86d8b56be51f8198618e309.jpg";
networkImageView.setImageUrl(url,new ImageLoader(queue,new BitmapCache()));
}
在onCreate方法中调用
private NetworkImageView networkImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
networkImageView=findViewById(R.id.networkImageView);
//创建一个请求队列
queue= Volley.newRequestQueue(this);
networkImageView();
}
当启动程序时,就会显示
NetworkImageView在加载图片时会自动获取自身的宽高,然后对比网络图片的宽高,再决定是否需要对图片进行压缩。压缩过程是在内部完全自动化,并不需要我们设置。
自定义XMLRequest
参考https://www.tuicool.com/articles/QbiU3q
新建XMLRequest类,继承Volley的Request:
package com.example.volly;
import android.util.Xml;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
public class XMLRequest extends Request<XmlPullParser> {
private final Response.Listener<XmlPullParser> xmlPullParserListener;
public XMLRequest(int method,String url,Response.Listener<XmlPullParser> xmlPullParserListener, Response.ErrorListener errorListener) {
super(method,url,errorListener);
this.xmlPullParserListener = xmlPullParserListener;
}
@Override
protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
try {
String xmlString=new String(response.data, HttpHeaderParser.parseCharset(response.headers));
XmlPullParser pull= Xml.newPullParser();
pull.setInput(new StringReader(xmlString));
return Response.success(pull,HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return Response.error(new ParseError(e));
} catch (XmlPullParserException e) {
e.printStackTrace();
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(XmlPullParser response) {
xmlPullParserListener.onResponse(response);
}
}
调用方法
XMLRequest xmlRequest = new XMLRequest(Request.Method.GET,
"http://flash.weather.com.cn/wmaps/xml/china.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 ("city".equals(nodeName)) {
String pName = new String(response.getAttributeValue(0).getBytes("iso8859-1"), "UTF-8");//解决乱码问题
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);
}
});
queue.add(xmlRequest);
自定义GsonRequest
参考https://www.tuicool.com/articles/QbiU3q
新建GsonRequest类,继承Volley的Request:
package com.example.volly;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import java.io.UnsupportedEncodingException;
public class GsonRequest<T> extends Request<T> {
private final Response.Listener<T> mListener;
private Gson gson;
private Class<T> mClass;
public GsonRequest(int method, String url,Class mclass, Response.Listener<T> mlistener, Response.ErrorListener errorListener) {
super(method,url,errorListener);
this.mListener = mlistener;
this.mClass=mclass;
}
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
try {
String jsonString=new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(gson.fromJson(jsonString,mClass),HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T t) {
mListener.onResponse(t);
}
}
新建一个Weather类
private WeatherInfo weatherinfo;
public WeatherInfo getWeatherinfo() {
return weatherinfo;
}
public void setWeatherinfo(WeatherInfo weatherinfo) {
this.weatherinfo = weatherinfo;
}
接着新建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;
}
调用GsonRequest
GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(
"http://www.weather.com.cn/data/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);
}
});
queue.add(gsonRequest);
但是最后的结果显示中文乱码,求解
Volley工作流程