十分详细又浅显易懂的Volley使用解析。
完整代码已上传到github,需要的可以自行download或者clone。
Volley是Android网络开发过程中十分重要的一个网络框架,基本都会用到,在这里总结一下Volley的特点和使用过程中需要注意的一些问题。
一、Volley特点:
1). 自动调度网络请求
2). 多个并发的网络连接----一个缓存线程,4个网络线程
3). 高效的Get/Post数据请求交互;
4). 网络图片加载和缓存;
5). 谷歌官方推出的,性能也比较稳定。
6). 特别适合数据量小,通信频繁的网络操作
图片加载效率一般
二、Volley的基本使用:
1. get和post请求
对象:StringRequest、JsonObjectRequest、JsonArrayRequest。根据数据类型选择合适的对象,一般StringRequest包含JsonObjectRequest、JsonArrayRequest这两种对象。
回调:两个接口Listener和ErrorListener
2. Volley的网络请求队列建立和取消队列请求
建立请求队列
取消某个请求或者所有请求
3. Volley与Activity生命周期的联动
特点:可以在Activity被销毁的同时关闭请求
关键点:设置Tag标签,onStop()方法中执行取消操作
4. Volley的简单二次回调封装
全局使用一个方式,可控,可自定义定制需求,方便,灵活
5. 使用ImageRequest获取网络图片
通过创建ImageRequest对象,传入url和Listener回调接口,最后显示图片
6. 使用ImageLoader缓存加载网络图片
通过ImageLoader、ImageListener、ImageCache或者LruCache来完成
三、Volley的详细使用
为了防止资源浪费,在Application中定义RequestQueue,并提供一个getQueues()方法,返回RequestQueue对象。
public class MyApplication extends Application {
public static RequestQueue queues;
@Override
public void onCreate() {
super.onCreate();
queues = Volley.newRequestQueue(getApplicationContext());
}
public static RequestQueue getQueues() {
return queues;
}
}
1. get请求
1) 使用StringRequest获取网络数据
private void volleyGet() {
//通过StringRequest获取
String url = "自己想要访问的网络数据的url";
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(MainActivity.this, volleyError.toString(), Toast.LENGTH_SHORT).show();
}
});
request.setTag("StringRequestGet");
MyApplication.getQueues().add(request);
}
2) 使用JsonObjectRequest获取网络数据
private void volleyGet() {
String url = "自己想要访问的网络数据的url";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Toast.makeText(MainActivity.this, jsonObject.toString(), Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(MainActivity.this, volleyError.toString(), Toast.LENGTH_SHORT).show();
}
});
request.setTag("JsonObjectStringGet");
MyApplication.getQueues().add(request);
}
3) 使用JsonArrayRequest获取网络数据
private void volleyGet() {
String url = "自己想要访问的网络数据的url";
JsonArrayRequest request = new JsonArrayRequest(url, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray jsonArray) {
Toast.makeText(MainActivity.this, jsonArray.toString(), Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(MainActivity.this, volleyError.toString(), Toast.LENGTH_SHORT).show();
}
});
request.setTag("JsonObjectStringGet");
MyApplication.getQueues().add(request);
}
其实使用StringRequest、JsonObjectRequest或者JsonArrayRequest取决于网络数据的格式,一般可以直接使用StringRequest获取,再对获取到的数据进行处理,对于Json格式的数据使用JsonObjectRequest效率能高一点,Array类型的数据类似。
2. post请求
1) 使用StringRequest网络数据获取
private void volleyPost() {
String url = "自己想要访问的网络数据的url";
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(MainActivity.this, volleyError.toString(), Toast.LENGTH_SHORT).show();
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> hashMap = new HashMap<>();
hashMap.put("key", "value");
return hashMap;
}
};
request.setTag("StringRequestPost");
MyApplication.getQueues().add(request);
}
2) 使用JsonObjectRequest获取网络数据
使用过程中遇到的最大的一个坑就是,在post传参的时候使用的是HashMap,然后就HashMap转换成JsonObject对象,但是,要考虑到服务器是否能接受Json格式的数据,否则就是获取不到数据。
a. 服务器支持Json格式
private void volleyPost() {
String url = "http://apis.juhe.cn/mobile/get?";
Map<String, String> hashMap = new HashMap<>();
hashMap.put("key", "value");
JSONObject object = new JSONObject(hashMap);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, object, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Log.i("TAG",jsonObject.toString());
Toast.makeText(MainActivity.this, jsonObject.toString(), Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(MainActivity.this, volleyError.toString(), Toast.LENGTH_SHORT).show();
}
});
request.setTag("Post");
MyApplication.getQueues().add(request);
}
b. 服务器不支持Json格式的数据
说实话,从网上找的解决办法,有两种,第一种是将传入的url直接写成String类型,经过自定义JsonObjectRequest来实现,呵呵,没有用的;第二种就是在JsonObjectRequest中定义和重写一大堆乱七八糟的代码,看不懂,没用,总而言之,Google推出这个Volley,能不能封装好了给我们来使用,看了一大堆源码和解决方法还是没有用,建议不要使用JsonObjectRequest,直接使用StringRequest。
3. Volley和Activity的联动
在onStop()方法中处理
protected void onStop() {
super.onStop();
MyApplication.getQueues().cancelAll("Get");
MyApplication.getQueues().cancelAll("Post");
}
4. Volley的简单二次封装
对Volley的封装主要就是三步:以StringRequest为例
第一步 封装两个回调接口Listener和ErrorListener,并添加两个抽象方法,方便重写。如下
public abstract class VolleyInterface {
public Context mContext;
public static Response.Listener listener;
public static Response.ErrorListener errorListener;
public abstract void onSuccess(Object result);
public abstract void onError(VolleyError result);
public VolleyInterface(Context mContext, Response.Listener listener, Response.ErrorListener errorListener) {
this.mContext = mContext;
this.listener = listener;
this.errorListener = errorListener;
}
//成功时回调的接口,同时调用onSuccess()方法
public Response.Listener succeedListener(){
listener = new Response.Listener() {
@Override
public void onResponse(Object response) {
onSuccess(response);
}
};
return listener;
}
//失败时回调的接口,同时调用errorListener()方法
public Response.ErrorListener errorListener(){
errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onError(error);
}
};
return errorListener;
}
}
第二步 封装VolleyRequest请求
public class VolleyRequest {
public static StringRequest request;
public static Context mContext;
public static void RequestGet(Context mContext, String url, String tag,VolleyInterface vif) {
MyApplication.getQueues().cancelAll(tag);
//创建StringRequest对象时,传入两个回调接口
request = new StringRequest(Request.Method.GET, url, vif.succeedListener(),vif.errorListener);
request.setTag(tag);
MyApplication.getQueues().add(request);
}
public static void RequestPost(Context mContext, String url, String tag, final Map<String,String> params, VolleyInterface vif) {
MyApplication.getQueues().cancelAll(tag);
//创建StringRequest对象时,传入两个回调接口,以及重写getParams()方法
request = new StringRequest(Request.Method.POST,url,vif.succeedListener(),vif.errorListener){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
return params;
}
};
request.setTag(tag);
MyApplication.getQueues().add(request);
}
}
第三步 在Activity中使用封装好的类来访问数据
String url = "自己想要访问的网络数据的url";
VolleyRequest.RequestGet(this, url, "Get", new VolleyInterface(this,VolleyInterface.listener,VolleyInterface.errorListener) {
@Override
public void onSuccess(Object result) {
Toast.makeText(MainActivity.this, result.toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void onError(VolleyError result) {
Toast.makeText(MainActivity.this, result.toString(), Toast.LENGTH_SHORT).show();
}
});
5. 使用ImageRequest获取网络图片
这个简单,通过创建ImageRequest对象,传入url和Listener回调接口,最后显示图片
String url = "https://ws1.sinaimg.cn/large/0065oQSqly1fuo54a6p0uj30sg0zdqnf.jpg";
ImageRequest imageRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, width, height, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
}
});
imageRequest.setTag("image");
MyApplication.getQueues().add(imageRequest);
6. 使用ImageLoader缓存网络图片
通过ImageLoader、ImageListener、ImageCache或者LruCache来完成。
String url = "https://ws1.sinaimg.cn/large/0065oQSqly1fuo54a6p0uj30sg0zdqnf.jpg";
ImageLoader loader = new ImageLoader(MyApplication.getQueues(),new BitmapCache());
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
loader.get(url,listener);
还可以使用Volley自带的NetworkImageView
String url = "https://ws1.sinaimg.cn/large/0065oQSqly1fuo54a6p0uj30sg0zdqnf.jpg";
ImageLoader loader = new ImageLoader(MyApplication.getQueues(),new BitmapCache());
networkImageView.setDefaultImageResId(R.mipmip.ic_launcher);
networkImageView.setImageUrl(url,loader);