- 浏览: 636560 次
文章分类
最新评论
-
涛声依旧是:
怎么提示掉线,怎么才能在线
基于Tomcat7、Java、WebSocket的服务器推送聊天室 -
dcode:
楼主写的不错,正好遇到点问题,看着你的文章解决了,感谢分享。。 ...
在 Visual Studio 2010 中配置SharpPcap
Asynchronous HTTP Requests in Android Using Volley
Volley是Android开发者新的瑞士军刀,它提供了优美的框架,使得Android应用程序网络访问更容易和更快。Volley抽象实现了底层的HTTP Client库,让你不关注HTTP Client细节,专注于写出更加漂亮、干净的RESTful HTTP请求。另外,Volley请求会异步执行,不阻挡主线程。
Volley提供的功能
简单的讲,提供了如下主要的功能:
1、封装了的异步的RESTful 请求API;
2、一个优雅和稳健的请求队列;
3、一个可扩展的架构,它使开发人员能够实现自定义的请求和响应处理机制;
4、能够使用外部HTTP Client库;
5、缓存策略;
6、自定义的网络图像加载视图(NetworkImageView,ImageLoader等);
为什么使用异步HTTP请求?
Android中要求HTTP请求异步执行,如果在主线程执行HTTP请求,可能会抛出android.os.NetworkOnMainThreadException 异常。阻塞主线程有一些严重的后果,它阻碍UI渲染,用户体验不流畅,它可能会导致可怕的ANR(Application Not Responding)。要避免这些陷阱,作为一个开发者,应该始终确保HTTP请求是在一个不同的线程。
怎样使用Volley
这篇博客将会详细的介绍在应用程程中怎么使用volley,它将包括一下几方面:
1、安装和使用Volley库
2、使用请求队列
3、异步的JSON、String请求
4、取消请求
5、重试失败的请求,自定义请求超时
6、设置请求头(HTTP headers)
7、使用Cookies
8、错误处理
安装和使用Volley库
引入Volley非常简单,首先,从git库先克隆一个下来:
git clone https://android.googlesource.com/platform/frameworks/volley
然后编译为jar包,再把jar包放到自己的工程的libs目录。
使用请求队列
Volley的所有请求都放在一个队列,然后进行处理,这里是你如何将创建一个请求队列:
RequestQueue mRequestQueue = Volley.newRequestQueue(this); // 'this' is Context
理想的情况是把请求队列集中放到一个地方,最好是初始化应用程序类中初始化请求队列,下面类做到了这一点:
public class ApplicationController extends Application {
/**
* Log or request TAG
*/
public static final String TAG = "VolleyPatterns";
/**
* Global request queue for Volley
*/
private RequestQueue mRequestQueue;
/**
* A singleton instance of the application class for easy access in other places
*/
private static ApplicationController sInstance;
@Override
public void onCreate() {
super.onCreate();
// initialize the singleton
sInstance = this;
}
/**
* @return ApplicationController singleton instance
*/
public static synchronized ApplicationController getInstance() {
return sInstance;
}
/**
* @return The Volley Request queue, the queue will be created if it is null
*/
public RequestQueue getRequestQueue() {
// lazy initialize the request queue, the queue instance will be
// created when it is accessed for the first time
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
/**
* Adds the specified request to the global queue, if tag is specified
* then it is used else Default TAG is used.
*
* @param req
* @param tag
*/
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
VolleyLog.d("Adding request to queue: %s", req.getUrl());
getRequestQueue().add(req);
}
/**
* Adds the specified request to the global queue using the Default TAG.
*
* @param req
* @param tag
*/
public <T> void addToRequestQueue(Request<T> req) {
// set the default tag if tag is empty
req.setTag(TAG);
getRequestQueue().add(req);
}
/**
* Cancels all pending requests by the specified TAG, it is important
* to specify a TAG so that the pending/ongoing requests can be cancelled.
*
* @param tag
*/
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
异步的JSON、String请求
Volley提供了以下的实用工具类进行异步HTTP请求:
- JsonObjectRequest— To send and receive JSON Object from the Server
- JsonArrayRequest— To receive JSON Array from the Server
- StringRequest— To retrieve response body as String (ideally if you intend to parse the response by yourself)
JsonObjectRequest
这个类可以用来发送和接收JSON对象。这个类的一个重载构造函数允许设置适当的请求方法(DELETE,GET,POST和PUT)。如果您正在使用一个RESTful服务端,可以使用这个类。下面的示例显示如何使GET和POST请求。GET请求:
final String URL = "/volley/resource/12"; // pass second argument as "null" for GET requests JsonObjectRequest req = new JsonObjectRequest(URL, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { VolleyLog.v("Response:%n %s", response.toString(4)); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e("Error: ", error.getMessage()); } }); // add the request object to the queue to be executed ApplicationController.getInstance().addToRequestQueue(req);
POST请求:
final String URL = "/volley/resource/12"; // Post params to be sent to the server HashMap<String, String> params = new HashMap<String, String>(); params.put("token", "AbCdEfGh123456"); JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params), new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { VolleyLog.v("Response:%n %s", response.toString(4)); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e("Error: ", error.getMessage()); } }); // add the request object to the queue to be executed ApplicationController.getInstance().addToRequestQueue(req);
JsonArrayRequest
这个类可以用来接受 JSON Arrary,不支持JSON Object。这个类现在只支持 HTTP GET。由于支持GET,你可以在URL的后面加上请求参数。类的构造函数不支持请求参数。
final String URL = "/volley/resource/all?count=20"; JsonArrayRequest req = new JsonArrayRequest(URL, new Response.Listener<JSONArray> () { @Override public void onResponse(JSONArray response) { try { VolleyLog.v("Response:%n %s", response.toString(4)); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e("Error: ", error.getMessage()); } }); // add the request object to the queue to be executed ApplicationController.getInstance().addToRequestQueue(req);
StringRequest
这个类可以用来从服务器获取String,如果想自己解析请求响应可以使用这个类,例如返回xml数据。它还可以使用重载的构造函数定制请求。
final String URL = "/volley/resource/recent.xml"; StringRequest req = new StringRequest(URL, new Response.Listener<String>() { @Override public void onResponse(String response) { VolleyLog.v("Response:%n %s", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e("Error: ", error.getMessage()); } }); // add the request object to the queue to be executed ApplicationController.getInstance().addToRequestQueue(req);
取消请求
Volley提供了强大的API取消未处理或正在处理的请求。取消请求最简单的方法是调用请求队列cancelAll(tag)的方法,前提是你在添加请求时设置了标记。这样就能使标签标记的请求挂起。
给请求设置标签:
request.setTag("My Tag");
使用ApplicationController添加使用了标签的请求到队列中:
ApplicationController.getInstance().addToRequestQueue(request, "My Tag");
取消所有指定标记的请求:
mRequestQueue.cancelAll("My Tag");
重试失败的请求,自定义请求超时
Volley中没有指定的方法来设置请求超时时间,可以设置RetryPolicy 来变通实现。DefaultRetryPolicy类有个initialTimeout参数,可以设置超时时间。要确保最大重试次数为1,以保证超时后不重新请求。
<figure class="code" style="margin: 10px 0px 1.5em; padding: 5px 15px; background-color: rgb(221, 221, 221); border: 1px solid rgb(204, 204, 204); border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; color: rgb(51, 51, 51); font-family: 'Source Sans Pro', sans-serif; font-size: 16px; line-height: 24px;"><figcaption style="margin: 0px; padding: 0px; font-size: 0.9em; position: relative;"><span style="margin: -5px -15px 0px; padding: 5px 15px; display: block; background-image: -webkit-linear-gradient(top, rgb(204, 204, 204), rgb(221, 221, 221)); background-position: initial initial; background-repeat: initial initial;">Setting Request Timeout</span></figcaption><div class="highlight" style="margin: 0px; padding: 0px; overflow-x: auto;"><table style="margin: 0px; padding: 0px; border: none; border-spacing: 0px; line-height: 1.2em;"><tbody style="margin: 0px; padding: 0px;"><tr style="margin: 0px; padding: 0px;"> <td class="gutter" style="margin: 0px; padding: 0px;"><pre class="line-numbers" style="margin-top: 0px; margin-bottom: 0px; padding: 0px 15px 0px 0px; background-image: none; border-right-width: 1px; border-style: none solid none none; border-right-color: rgb(204, 204, 204); font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.9; overflow-x: auto; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; text-align: right; font-size: 0.8em;"><span class="line-number" style="margin: 0px; padding: 0px;">1</span> </pre></td> <td class="code" style="margin: 0px; padding: 0px 0px 0px 15px; width: 731px;"> <pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; background-image: none; border: none; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; line-height: 1.5; overflow-x: auto; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px;"><code class="java" style="margin: 0px; padding: 0px; background-image: none; border: none; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; font-size: 0.8em; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; background-position: initial initial; background-repeat: initial initial;"><span class="n" style="margin: 0px; padding: 0px; color: rgb(38, 139, 210) !important;">request</span><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">.</span><span class="na" style="margin: 0px; padding: 0px; color: rgb(38, 139, 210) !important;">setRetryPolicy</span><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">(</span><span class="k" style="margin: 0px; padding: 0px; color: rgb(203, 75, 22) !important;">new</span> <span class="n" style="margin: 0px; padding: 0px; color: rgb(38, 139, 210) !important;">DefaultRetryPolicy</span><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">(</span><span class="mi" style="margin: 0px; padding: 0px; color: rgb(42, 161, 152) !important;">20</span> <span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">*</span> <span class="mi" style="margin: 0px; padding: 0px; color: rgb(42, 161, 152) !important;">1000</span><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">,</span> <span class="mi" style="margin: 0px; padding: 0px; color: rgb(42, 161, 152) !important;">1</span><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">,</span> <span class="mf" style="margin: 0px; padding: 0px; color: rgb(42, 161, 152) !important;">1.0f</span><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;">));</span> </code></pre> <div><code class="java" style="margin: 0px; padding: 0px; background-image: none; border: none; font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace; font-size: 0.8em; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; background-position: initial initial; background-repeat: initial initial;"><span class="o" style="margin: 0px; padding: 0px; color: rgb(147, 161, 161) !important; font-weight: bold !important;"><br></span></code></div> </td> </tr></tbody></table></div></figure> 如果你想失败后重新请求(因超时),您可以指定使用上面的代码,增加重试次数。注意最后一个参数,它允许你指定一个退避乘数可以用来实现“指数退避”来从RESTful服务器请求数据。
设置请求头(HTTP headers)
有时候需要给HTTP请求添加额外的头信息,一个常用的例子是添加 “Authorization”到HTTP 请求的头信息。Volley请求类提供了一个 getHeaers()的方法,重载这个方法可以自定义HTTP 的头信息。
添加头信息:
JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params), new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { // handle response } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // handle error } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { HashMap<String, String> headers = new HashMap<String, String>(); headers.put("CUSTOM_HEADER", "Yahoo"); headers.put("ANOTHER_CUSTOM_HEADER", "Google"); return headers; } };
使用Cookies
Volley中没有直接的API来设置cookies,Volley的设计理念就是提供干净、简洁的API来实现RESTful HTTP请求,不提供设置cookies是合理的。
下面是修改后的ApplicationController类,这个类修改了getRequestQueue()方法,包含了 设置cookie方法,这些修改还是有些粗糙。
// http client instance private DefaultHttpClient mHttpClient; public RequestQueue getRequestQueue() { // lazy initialize the request queue, the queue instance will be // created when it is accessed for the first time if (mRequestQueue == null) { // Create an instance of the Http client. // We need this in order to access the cookie store mHttpClient = new DefaultHttpClient(); // create the request queue mRequestQueue = Volley.newRequestQueue(this, new HttpClientStack(mHttpClient)); } return mRequestQueue; } /** * Method to set a cookie */ public void setCookie() { CookieStore cs = mHttpClient.getCookieStore(); // create a cookie cs.addCookie(new BasicClientCookie2("cookie", "spooky")); } // add the cookie before adding the request to the queue setCookie(); // add the request to the queue mRequestQueue.add(request);
错误处理
正如前面代码看到的,在创建一个请求时,需要添加一个错误监听onErrorResponse。如果请求发生异常,会返回一个VolleyError实例。
以下是Volley的异常列表:
可以使用一个简单的Help类根据这些异常提示相应的信息:AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。
NetworkError:Socket关闭,服务器宕机,DNS错误都会产生这个错误。
NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。
ParseError:在使用JsonObjectRequest或JsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。
SERVERERROR:服务器的响应的一个错误,最有可能的4xx或5xx HTTP状态代码。
TimeoutError:Socket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy。
public class VolleyErrorHelper { /** * Returns appropriate message which is to be displayed to the user * against the specified error object. * * @param error * @param context * @return */ public static String getMessage(Object error, Context context) { if (error instanceof TimeoutError) { return context.getResources().getString(R.string.generic_server_down); } else if (isServerProblem(error)) { return handleServerError(error, context); } else if (isNetworkProblem(error)) { return context.getResources().getString(R.string.no_internet); } return context.getResources().getString(R.string.generic_error); } /** * Determines whether the error is related to network * @param error * @return */ private static boolean isNetworkProblem(Object error) { return (error instanceof NetworkError) || (error instanceof NoConnectionError); } /** * Determines whether the error is related to server * @param error * @return */ private static boolean isServerProblem(Object error) { return (error instanceof ServerError) || (error instanceof AuthFailureError); } /** * Handles the server error, tries to determine whether to show a stock message or to * show a message retrieved from the server. * * @param err * @param context * @return */ private static String handleServerError(Object err, Context context) { VolleyError error = (VolleyError) err; NetworkResponse response = error.networkResponse; if (response != null) { switch (response.statusCode) { case 404: case 422: case 401: try { // server might return error like this { "error": "Some error occured" } // Use "Gson" to parse the result HashMap<String, String> result = new Gson().fromJson(new String(response.data), new TypeToken<Map<String, String>>() { }.getType()); if (result != null && result.containsKey("error")) { return result.get("error"); } } catch (Exception e) { e.printStackTrace(); } // invalid request return error.getMessage(); default: return context.getResources().getString(R.string.generic_server_down); } } return context.getResources().getString(R.string.generic_error); } }
总结:
Volley是一个非常好的库,你可以尝试使用一下,它会帮助你简化网络请求,带来更多的益处。
我也希望更加全面的介绍Volley,以后可能会介绍使用volley加载图像的内容,欢迎关注。
谢谢你的阅读,希望你能喜欢。
参考:
- NetworkOnMainThreadException —http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
- Application —http://developer.android.com/reference/android/app/Application.html
原文:
http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/
相关推荐
Asynchronous Http Client for Android An asynchronous, callback-based Http client for Android built on top of Apache's HttpClient ...Make asynchronous HTTP requests, handle responses in anonymous call
A C library for asynchronous DNS requests
Asynchronous programming has acquired immense importance in Android programming, especially when we want to make use of the number of independent processing units (cores) available on the most recent ...
// 1.创建异步请求的客户端对象 ...其他有什么问题或者想具体了解详细说明,可以参考官网 http://loopj.com/android-async-http/ 其他参考链接 http://blog.csdn.net/redarmy_chen/article/details/26980613
Make asynchronous HTTP requests, handle responses in anonymous callbacks HTTP requests happen outside the UI thread Requests use a threadpool to cap concurrent resource usage GET/POST params builder ...
Asynchronous programming has acquired immense importance in Android programming, especially when we want to make use of the number of independent processing units (cores) available on the most recent ...
Asynchronous Android Programming 2nd 第2版 英文pdf
RoboSpice is a modular android library that makes writing asynchronous network requests easy ! To learn more about RoboSpice in 30 seconds, try [this infographics] ...
1.Android Asynchronous Http Client 2.okhttp square开发并且开源的,因为之前用过他们家的picasso,所以对这套满有好感的,只可惜使用方式不太喜欢 3.Volley Volley是Google在2013年Google I/O的时候发布的,到...
Using it, you can easily create an asynchronous HTTP request and receive event callback. It can be applied to MFC and ATL projects. This code mainly consists of two classes: class FCHttpRequest and ...
Asynchronous Procedure Calls ,也就是异步过程调用,这份文档是内核中APC的详尽介绍,值得一看
Asynchronous Registry Notification Using Strongly-typed WMI Classes in .NET.
First of all, the book will lead a developer through RxJava an initial setup in Android environment in Part 1. Later in the second part the reader will learn RxJava 2.0 step-by-step by starting off ...
A cross-platform asynchronous HTTP(S) proxy server in C#.
The Node.js runtime has become a major platform for de- velopers building cloud, mobile, or IoT applications using JavaScript. Since the JavaScript language is single threaded, Node.js programs must ...
Android Asynchronous HTTPClient的实现和优化
In this book a novice developer will be introduced to a wide variety of tools that RxJava provides to enable them to produce robust and high-quality code for their asynchronous tasks by building a ...
框架目前主要包含的功能有View ...UltimateAndroid框架是如同flask框架(python)那样包含了许多其他的开源项目的框架,比如 Butter Knife,Asynchronous Http Client for Android, Universal Image Loader for Android
This practical book describes many asynchronous mechanisms available in the Android Sdk, and provides guidelines for selecting the ones most appropriate for the app you&#8217;re building.Author ...