本文github地址:
https://github.com/YoungBear/MyBlog/blob/master/VolleyLearn.md
Volley是Android下个一个网络请求库,它可以让Android下的网络访问更加简单和快速。默认情况下,Volley都是异步访问网络的,所以我们不必担心异步处理问题。
Volley的优点:
- 请求队列和请求优先级
- 请求Cache和内存管理
- 扩展性性强
- 可以取消请求
导入Volley的方法
第一种
在build.gradle中添加dependency:
dependencies {
...
compile 'com.android.volley:volley:1.0.0'
}
第二种
使用源代码,作为一个library project。
git clone https://android.googlesource.com/platform/frameworks/volley
另外,也可以在源代码中导出jar包,使用jar包作为库。
使用Volley进行网络请求
首先,在AndroidManifest.xml中添加网络访问权限,
<uses-permission android:name="android.permission.INTERNET"/>
使用一个单例来管理请求(一般可以继承Application)
//VolleyController.java
public class VolleyController {
public static final String TAG = VolleyController.class.getSimpleName();
private static volatile VolleyController mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mContext;
private VolleyController(Context context) {
mContext = context.getApplicationContext();
mRequestQueue = Volley.newRequestQueue(mContext);
mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache());
}
public static VolleyController getInstance(Context context) {
if (mInstance == null) {
synchronized (VolleyController.class) {
if (mInstance == null) {
mInstance = new VolleyController(context);
}
}
}
return mInstance;
}
public RequestQueue getRequestQueue() {
return mRequestQueue;
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
mRequestQueue.add(req);
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
mRequestQueue.add(req);
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
还需要一个Cache来存放请求的图片:
//LruBitmapCache.java
public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache{
public static int getDefaultLruCacheSize() {
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
return cacheSize;
}
public LruBitmapCache() {
this(getDefaultLruCacheSize());
}
public LruBitmapCache(int sizeInKiloBytes) {
super(sizeInKiloBytes);
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
@Override
public Bitmap getBitmap(String url) {
return get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
String Request
新建一个Request并且把他加入到请求队列中RequestQueue:
private void simpleRequest() {
StringRequest stringRequest = new StringRequest(
Request.Method.GET,
TEST_URL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d(TAG, "onResponse, response: " + response);
txtDisplay.setText("Response is: " + response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "onErrorResponse, error: " + error.getMessage());
txtDisplay.setText("That didn't work!");
}
});
VolleyController.getInstance(this).addToRequestQueue(stringRequest, TAG);
}
Volley工作原理图
在Activity的onStop()方法中cancel所有标记为该TAG的请求:
@Override
protected void onStop() {
super.onStop();
VolleyController.getInstance(this).cancelPendingRequests(TAG);
}
创建POST请求
上面说的都是GET请求,下面来说一下POST请求,与GET请求不同的是,只要在创建请求的时候将请求类型改为POST请求,并且override Request的getParams方法即可。
添加请求头部信息
override Request的getHeaders方法。
private void simplePostRequest() {
StringRequest stringRequest = new StringRequest(
Request.Method.POST,
TEST_URL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d(TAG, "post, onResponse, response: " + response);
txtDisplay.setText("Response is: " + response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "post, onErrorResponse, error: " + error.getMessage());
txtDisplay.setText("That didn't work!");
}
}
) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("name", "Androidhive");
params.put("email", "abc@androidhive.info");
params.put("password", "password123");
return params;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("apiKey", "xxxxxxxxxxxxxxx");
return headers;
}
};
//关闭Cache
stringRequest.setShouldCache(false);
VolleyController.getInstance(this).addToRequestQueue(stringRequest, TAG);
}
创建Image请求
Volley库中自带了NetworkImageView类,这个ImageView可以自动使用volley下载图片。
使用ImageRequest
private void imageRequest() {
ImageRequest imageRequest = new ImageRequest(
TEST_URL_1,
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
mImageView.setImageBitmap(response);
}
}, 0, 0, null,
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "onErrorResponse, error: " + error.getMessage());
}
}
);
VolleyController.getInstance(this).addToRequestQueue(imageRequest, TAG);
}
ImageRequest构造函数源代码:
@Deprecated
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
Config decodeConfig, Response.ErrorListener errorListener) {
this(url, listener, maxWidth, maxHeight,
ScaleType.CENTER_INSIDE, decodeConfig, errorListener);
}
可以看到,ImageRequest的构造函数接收6个参数
- 第一个参数是图片的URL地址
- 第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中
- 第三和第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不进行压缩。
- 第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个人字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。
- 第六个参数是图片请求失败的回调,我们可以在请求失败时显示一张失败的图片。
使用ImageLoader
ImageLoader也可以用于加载网络上的图片,并且它的内部也是使用ImageRequest来实现的,不过ImageLoader明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
由于ImageLoader已经不是继承自Request的了,所以它的用法也和我们之前学到的内容有所不同,总结起来大致可以分为以下四步:
- 创建一个RequestQueue对象
- 创建一个ImageLoader对象
- 获取一个ImageListener对象
- 调用ImageLoader的get()方法加载网络上的图片
private void imageLoaderGet() {
ImageLoader imageLoader = VolleyController.getInstance(this).getImageLoader();
imageLoader.get(TEST_URL_3, new ImageLoader.ImageListener() {
@Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
mImageView3.setImageBitmap(response.getBitmap());
}
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Image Load Error: " + error.getMessage());
}
});
}
使用NetworkImageView
NetworkImageView是一个自定义控件,它是继承自ImageView的,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能。
使用方法:
- 在布局文件中添加NetworkImageView
- 获取ImageLoader
- 调用NetworkImageView的setImageUrl()方法
//...
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/network_img_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
mNetworkImageView = (NetworkImageView) findViewById(R.id.network_img_display);
private void setNetworkImageView() {
ImageLoader imageLoader = VolleyController.getInstance(this).getImageLoader();
mNetworkImageView.setImageUrl(TEST_URL_2, imageLoader);
}
JSON Request
private void jsonRequest() {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
Request.Method.GET,
TEST_URL,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
txtDisplay.setText(response.toString());
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse, error: " + error.getMessage());
}
});
VolleyController.getInstance(this).addToRequestQueue(jsonObjectRequest, TAG);
}
private void jsonArrayRequest() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(
Request.Method.GET,
TEST_URL2,
null,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
txtDisplay.setText(response.length() + "\n" + response.toString());
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse, error: " + error.getMessage());
}
}
);
VolleyController.getInstance(this).addToRequestQueue(jsonArrayRequest, TAG);
}
自定义Requet
在build.gradle文件中添加gson依赖:
dependencies {
...
compile 'com.google.code.gson:gson:2.7'
}
自定义GsonRequest:
//GsonRequest.java
public class GsonRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Response.Listener<T> listener;
public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
Listener<T> listener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
}
在实际调用的时候,和普通的请求类似:
private void personRequest() {
GsonRequest<Person> gsonRequest = new GsonRequest<Person>(
TEST_URL,
Person.class,
null,
new Response.Listener<Person>() {
@Override
public void onResponse(Person response) {
txtDisplay.setText("size: " + response.getContacts().size());
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse, error: " + error.getMessage());
}
}
);
VolleyController.getInstance(this).addToRequestQueue(gsonRequest, TAG);
}
实体类Person类:(在AS下可以使用gson插件来生成)
package com.example.volleylearn.model;
import java.util.List;
/**
* Created by youngbear on 16/10/18.
*/
public class Person {
/**
* id : c200
* name : Ravi Tamada
* email : ravi@gmail.com
* address : xx-xx-xxxx,x - street, x - country
* gender : male
* phone : {"mobile":"+91 0000000000","home":"00 000000","office":"00 000000"}
*/
private List<ContactsBean> contacts;
public List<ContactsBean> getContacts() {
return contacts;
}
public void setContacts(List<ContactsBean> contacts) {
this.contacts = contacts;
}
public static class ContactsBean {
private String id;
private String name;
private String email;
private String address;
private String gender;
/**
* mobile : +91 0000000000
* home : 00 000000
* office : 00 000000
*/
private PhoneBean phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public PhoneBean getPhone() {
return phone;
}
public void setPhone(PhoneBean phone) {
this.phone = phone;
}
public static class PhoneBean {
private String mobile;
private String home;
private String office;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getOffice() {
return office;
}
public void setOffice(String office) {
this.office = office;
}
}
}
}
测试代码位置:https://github.com/YoungBear/VolleyLearn
参考:
http://www.androidhive.info/2014/05/android-working-with-volley-library-1/
http://bxbxbai.github.io/2014/09/14/android-working-with-volley/
https://developer.android.com/training/volley/index.html
http://blog.youkuaiyun.com/guolin_blog/article/details/17482165
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1018/1800.html