如何使用Volley?
使用之前,希望你看过之前的文档,知道Volley适合干啥?简单点说,就是小且高并发的请求适合使用Volley。我们App一般的接口请求具有上面的特点,所以适合使用。接下来,我们举三个栗子,来了解如何使用。
发送一个简单请求
从上层使用上来讲,我们通过创建一个RequestQueue,然后传递给它一个Reques对象来使用Volley。RequestQueue对象管理运行网络操作的工作线程,读取和写入缓存,和解析响应内容。Requests处理解析原始响应内容,然后,Volley照顾派发解析后的结果到主线程用于传送。
这段内容,我们先使用简单的方法-Volley.newRequestQueue创建一个请求。
1. 添加网络请求权限
额,比较简单,所有涉及到网络请求的应用都需要在AndroidManifest.xml中申请网络权限。代码简单,直接添加就行了。
<uses-permission android:name="android.permission.INTERNET" />
2. 使用Volley.newRequestQueue方法
我们使用这个方法来创建一个RequestQueue,不做任何请求配置,直接使用默认的配置。
final TextView mTextView = (TextView) findViewById(R.id.text);
// ...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.baidu.com";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
// mTextView.setText("Response is: "+ response.substring(0,500));
Log.e("VolleyTest","Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// mTextView.setText("That didn't work!");
Log.e("VolleyTest","Bad lucy,it didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
细心的你,应该已经注意到了,我们在初始化时,传入了当前Activity的context。
RequestQueue queue = Volley.newRequestQueue(this);
然后,我们创建了一个StringRequest。它是Request的子类。上面说过,我们的Request负责解析返回的内容,然后将解析后的对象给Volley,然后Volley将解析后得到的对象派发到主线程。StringRequst的构造函数,让我们传入四个参数,分别是:请求的方法类型,目标url,一个成功回调,和一个报错回调。我们在成功回调中拿到想要的数据,在失败回调中拿到失败的原因。需要我们注意的是:Volley将结果传递到主线程了,所以,我们能在回调中进行UI填充。这一点很爽啊,像OKhttp就不默认支持。如果要用的话,我们需要封装一下。Comes out of the box,哈哈,开箱即用。
3. 添加一个请求
你可以向上面那样,直接调用add()方法,将请求添加到RequestQueue。一旦你添加了它,它将移入流水线(pineline),获得服务,得到的原始响应数据被解析和传送到主线程(调用你设置好的回调)。
当你调用add()后,Volley将运行一个缓存处理线程和一个网络线程派发线程池。当你添加了一个请求到队列,它将被缓存线程选中,然后进行鉴别:
- 如果缓存能够为它提供服务,缓存过的响应内容在缓存处理线程解析,然后将解析后的对象传送到主线程。
- 如果不能,它将被放置到网路线程。第一个空闲的线程,将这个请求从队列中取出,执行HTTP事务,在工作线程解析原始结果。然后,将原始结果加入缓存。同时,将解析后的对象,递送到主线程来传递。
需要注意的是,阻塞I/O和解析/解码等耗时的操作是在工作线程上完成的。你可以从任何线程添加请求,但响应始终在主线程上传递。
纸上得来终觉浅,绝知此时要有图
4. 取消请求
阴阳相生,凡事有阴必有阳。有请求,总会有取消请求的需要。也许你现在不需要,总有一天你会需要。如何取消一个请求?只需要调用Request的cancle()方法即可。调用这个方法之后,Volley保证不会回调你设置的回调。哈哈,妈妈再也不用担心我的程序leakwindow了呢。
然鹅,你肯定会问,如果我要取消当前Activity或Fragment的所有的请求呢?难道一个一个去取消?那不要累死人啦。当然不是啦,我们也可以调用RequestQueue的cancelAll()方法,取消所有请求。额,对了,有两个重载方法分别是:
- public void cancelAll(final Object tag)
- public void cancelAll(RequestFilter filter)
所以,你可以给你的Request设置一个Tag或者filter,然后取消指定的分类。
- 给你的请求设置Tag
public static final String TAG = "MyTag";
StringRequest stringRequest; // Assume this exists.
RequestQueue mRequestQueue; // Assume this exists.
// Set the tag on the request.
stringRequest.setTag(TAG);
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
- 取消你的请求
@Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
需要注意的是,你不要随便的取消请求,特别是,你下一步的操作,一定需要请求到的数据。额,啰嗦。
创建一个RequestQueue
前面一个章节,我们使用Volley.newRequestQueue()方法创建了一个RequestQueue,Volley默认为我们设置好了一些配置。这一节,我们来个性化定制一下。
同时,这一节,我们还讲一下如何单例一个RequestQueue。
1. 设置网络和缓存
RequestQueue需要两件来完成它的工作:网络用来传输请求;缓存来处理完成缓存。在Volley的工具箱中有一些已经按照标准实现的类:DiskBasedCash提供一个内存索引的每一个请求一个文件的缓存;BaseNetwork基于你首选的HTTP客户端来提供网络传输。
BaseNetwork是volley默认的网络实现。BaseNetwork必须和HTTP客户端一起初始化,HTTP客户端是你的Appy用来连接网络。典型的,它是HttpURLConnection。
接下来的代码,展示如何创建和设置RequestQueue。
RequestQueue mRequestQueue;
// Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);
// Start the queue
mRequestQueue.start();
String url ="http://www.example.com";
// Formulate the request and handle the response.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Do something with the response
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Handle error
}
});
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
// ...
如果你只需要一次请求,不想保留线程池,你可以在任何需要的地方创建RequestQueue,在得到数据或者失败回调之后,调用stop()方法。但是更常见的一个场景是,你需要创建一个单例的在整个App的生命周期中运行的RequestQueue。
2. 使用单例模式
如果你的应用程序不断使用网络,那么设置RequestQueue的单个实例可能是最有效的,该实例将持续你的应用程序的生命周期。你可以通过各种方式来实现这一目标。推荐的方式是实现一个单例的封装了RequestQueue和其它Volley功能的类。另外一种方式是在Application的子类的onCreate方法中设置RequestQueue。但是不鼓励使用这种方式;静态单例可以以更模块化的方式提供相同的功能。
一个关键的概念是:RequestQueue必须以Application而不是Activity的context初始化。这可确保RequestQueue将持续应用程序的生命周期,而不是每次重新创建Activity时重新创建(例如,当用户旋转设备时)。
下面举个例子:
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx;
private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
如何使用这个单例?
// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();
// ...
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
创建一个标准请求
Volley默认支持的请求结果:
- StringRequest 指定一个URL,获取到字符串数据。
- JsonObjectRequest 指定URL,获取到一个JsonObject
- JsonArrayRequest 同上获取到JsonArray
如果你恰好需要以上几种结果,那么,你直接使用标准的请求即可,而不是去实现一个自己个性化定制的Request。比较简单,直接给出代码。
String url = "http://my-json-feed";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
mTextView.setText("Response: " + response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle error
}
});
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
创建一个自定义的请求
如果标准请求不符合你想要的结果,你也可以自己创建一个个性化的请求。
1. 写一个自定义的请求
要写一个自定义的请求,你必须按照下面的做:
- 继承Request<T>类,<T>表示你的请求解析后想要得到的对象。这就是说,如果你想要的结果是String,创建自定义请求通过继承Request<String>。查看Volley默认支持的请求类型StringRequest和ImageRequest的代码作为示例。
- 实现抽象方法parseNetworkResponse()和deliverResponse(),详细信息如下:
parseNetworkResponse
Respouse封装了一个解析后的会被传递的给定类型的对象,例如:字符串、图片或者JSON。这有一个parseNetworkRewponse方法的代码。
@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));
}
// handle errors
// ...
}
注意:
- parseNetworkResponse() takes as its parameter a NetworkResponse, which contains the response payload as a byte[], HTTP status code, and response headers. parseNetworkResponse()将NetworkResponse作为它的参数,NetworkResponse包含了响应负载(作为bype[]),HTTP状态码,和响应的报文头。
- 你的实现必须返回Response<T>,其中包含了你定义的响应类型对象,和缓存的元数据或者错误,比如,在解析失败的情况下。
如果你的协议有非标准的缓存语义,你可以自己构建一个Cache.Entry,但大多数请求都可以这样:
return Response.success(myDecodedObject,
HttpHeaderParser.parseCacheHeaders(response));
Volley从工作线程调用parseNetworkResponse()。这确保了昂贵的解析操作(例如将JPEG解码为Bitmap)不会阻止UI线程。
deliverResponse
Volley使用你在parseNetworkResponse()中返回的对象调用主线程。大多数请求在此处调用回调接口,例如:
protected void deliverResponse(T response) {
listener.onResponse(response);
}
2. 示例:GsonRequest
Gson是一个使用反射将Java对象转换成字JSON串或将JSON串转换成Java对象的工具库。(Gson is a library for converting Java objects to and from JSON using reflection. )
你可以定义与其对应的JSON键具有相同名称的Java对象,将Gson传递给类对象,Gson将为你填写字段。
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 Listener<T> listener;
/**
* Make a GET request and return a parsed object from JSON.
*
* @param url URL of the request to make
* @param clazz Relevant class object, for Gson's reflection
* @param headers Map of request headers
*/
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 void deliverResponse(T response) {
listener.onResponse(response);
}
@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));
}
}
}
以上就是如何使用Volley的方法,接下来一章,我们开始分析Volley源码。
网友评论