Volley 是 Goole I/O 2013上发布的网络通信库,使网络通信更快、更简单、更健壮。 适用于数据不大但通信频繁的场景,不适合大文件下载。
- Json,图像等异步下载
- 网络请求的优先级处理
- 缓存
- 取消请求
- 线程管理
- 缓存的管理
- 发送网络请求过程
- 在主线程把请求加入请求队列
- 缓存线程查询请求是否有缓存,如果有缓存,则从缓存中获取数据解析返回给主线程,如果没有缓存,把请求分发给网络线程
- 网络线程发送请求,从服务器获取数据,解析后返回给主线程
<uses-permission android:name="android.permission.INTERNET"/>
compile 'com.android.volley:volley:1.0.0'
public void onStartStringRequest(View view) {
String url = "http://gank.io/api/data/Android/10/1";
StringRequest stringRequest = new StringRequest(url, mStringListener, mErrorListener);
Volley.newRequestQueue(this).add(stringRequest);
}
private Response.Listener<String> mStringListener = new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
}
};
private Response.ErrorListener mErrorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
}
};
public void onStartJsonObjectRequest(View view) {
String url = "http://gank.io/api/data/Android/10/1";
//Get请求第二个参数传null
//Post请求第二个参数传JsonObject对象
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, mJSONObjectListener, mErrorListener);
Volley.newRequestQueue(this).add(jsonObjectRequest);
}
private Response.Listener<JSONObject> mJSONObjectListener = new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
//获取网络响应中results数组中第一个元素的"desc"字段
String desc = response.getJSONArray("results").getJSONObject(0).getString("desc");
Toast.makeText(MainActivity.this, desc, Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
e.printStackTrace();
}
}
};
public void onStartJsonArrayRequest(View view) {
String url = "https://api.github.com/users/octocat/repos";
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url, mJSONArrayListener, mErrorListener);
Volley.newRequestQueue(this).add(jsonArrayRequest);
}
private Response.Listener<JSONArray> mJSONArrayListener = new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
try {
//获取数组中第一个元素的"name"字段
String name = response.getJSONObject(0).getString("name");
Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
e.printStackTrace();
}
}
};
public void onStartImageRequest(View view) {
String url = "https://ws1.sinaimg.cn/large/610dc034ly1fj3w0emfcbj20u011iabm.jpg";
//第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,
//则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。
ImageRequest request = new ImageRequest(url,
mBitmapListener,
0,
0,
Bitmap.Config.RGB_565,
mErrorListener);
Volley.newRequestQueue(this).add(request);
}
private Response.Listener<Bitmap> mBitmapListener = new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
mImageView.setImageBitmap(response);
}
};
一个应用只需一个RequestQueue, 不必每次发请求都创建一个请求队列。
public class NetworkManager {
private static NetworkManager sNetworkManager;
private RequestQueue mQueue;
public static NetworkManager getInstance() {
if (sNetworkManager == null) {
synchronized (NetworkManager.class) {
if (sNetworkManager == null) {
sNetworkManager = new NetworkManager();
}
}
}
return sNetworkManager;
}
public void init(Context context) {
mQueue = Volley.newRequestQueue(context);
}
public void sendRequest(Request request) {
mQueue.add(request);
}
}
public class NetworkListener<T> implements Response.Listener<T>, Response.ErrorListener{
@Override
public void onErrorResponse(VolleyError error) {
}
@Override
public void onResponse(T response) {
}
}
compile 'com.google.code.gson:gson:2.8.0'
public class GsonRequest<T> extends JsonRequest<T> {
public GsonRequest(int method, String url, String requestBody, Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(method, url, requestBody, listener, errorListener);
}
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
String parsedString;
try {
//将网络响应的字节数组转换成字符串
parsedString = new String(response.data, PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException e) {
}
}
//将字符串转换成java bean
T result = mGson.fromJson(parsedString, mClass);
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
//返回解析后的结果,使用Response对象包装
return Response.success(result, HttpHeaderParser.parseCacheHeaders(response));
}
public void onStartGsonRequest(View view) {
String url = "http://gank.io/api/data/Android/10/1";
GsonRequest<GankBean> request = new GsonRequest<GankBean>(GankBean.class, url, mGankBeanNetworkListener);
NetworkManager.getInstance().sendRequest(request);
}
mNetworkImageView = (NetworkImageView) findViewById(R.id.network_image_view);
mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
String url = "https://ws1.sinaimg.cn/large/610dc034ly1fj3w0emfcbj20u011iabm.jpg";
NetworkImageView.setImageUrl(url, NetworkManager.getInstance().getImageLoader());
ImageLoader是加载和缓存网络图片的工具。由于它也要用到RequestQueue, 一个应用也只需要一个ImageLoader,所以同样的封装到NetworkManager中。
public void init(Context context) {
mQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mQueue, new ImageLruCache(DEFAULT_IMAGE_CACHE_SIZE));
}
Least Recent Used。当访问一条数据时,数据会放在表头,当缓存超过最大值时,会删除表尾的数据。
/**
* 图片内存LRU缓存
*/
private static class ImageLruCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache{
public ImageLruCache(int maxSize) {
super(maxSize);
}
/**
* 返回对应key的bitmap的大小,当存入缓存时,要计算是否超出缓存的最大值
*/
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
/**
* 返回对应url的图片缓存
*/
@Override
public Bitmap getBitmap(String url) {
return get(url);
}
/**
* 存入缓存
*/
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
Volley的封装级别类似Retrofit,FunHttp。 Retrofit,FunHttp都是对OKhttp的一层封装,解决了数据转换和线程切换等问题。 Volley内部使用HttpClient或者HttpURLConnection完成网络请求,由于Volley的良好扩展性,还可以配置使用Okhttp进行网络请求。 可以看出HttpClient,HttpURLConnection,Okhttp属于同一层级,Retrofit,Volley,FunHttp属于同一层级。
- 磁盘缓存的初始化(DiskBasedCache)mCache
- 执行网络请求对象(Network)的创建 mNetwork
- 初始化网络请求的线程池mDispatchers = new NetworkDispatcher[threadPoolSize];,默认大小是4.
- 创建网络请求响应和错误的分发器mDelivery=new ExecutorDelivery(new Handler(Looper.getMainLooper()))
-
创建缓存分发器,启动该线程,执行run方法,run方法里面初始化磁盘缓存(把缓存文件的头读取出来,存入集合)
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start();
-
创建网络分发器并且启动
// Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); }
- 首先网络请求添加到缓存请求队列mCacheQueue,CacheDispatcher的run方法里面的监控mCacheQueue,如果mCacheQueue有请求,则拿出来,查看是否有缓存,如果有并且没有过期,则解析网络缓存的结果,分发到主线程
- 请求加入到网络请求队列mNetworkQueue,NetworkDispatcher的run方法里面监控mNetworkQueue,如果有请求,则拿出来发送网络请求,获取到结果后解析,然后存入缓存,最后分发到主线程。