Volley提供了优美的框架,使android程序网络访问更容易、更快。

Volley抽象实现了底层的HTTP Client库,我们不需关注HTTP Client细节,专注于写出更加漂亮、干净的RESTful HTTP请求。

Volley请求会异步执行,不阻挡主线程。

Volley提供的功能

  1. 封装了异步的RESTful请求API
  2. 一个优雅and稳健的请求队列
  3. 一个可扩展的架构,使开发者能实现自定义的请求和响应处理机制
  4. 能使用外部Http Client库
  5. 缓存策略
  6. 自定义的网络图像加载视图(NetworkImageView,ImageLoader等)

为什么使用异步Http请求

Android中要求HTTP请求异步执行,如果在主线程执行HTTP请求,可能会抛出 android.os.NetworkOnMainThreadException  异常。阻塞主线程有一些严重的后果,它阻碍UI渲染,用户体验不流 畅,它可能会导致可怕的ANR(Application Not Responding)。要避免这些陷阱,作为一个开发者,应该始终确保HTTP请求是在一个不同的线程

怎样使用Volley

1、安装和使用Volley库

2、使用请求队列

3、异步的JSON、String请求

4、取消请求

5、重试失败的请求,自定义请求超时

6、设置请求头(HTTP headers)

7、使用Cookies

8、错误处理

1.安装和使用Volley库

引入Volley非常简单,首先,从git库先克隆一个下来:

  1. git clone https://android.googlesource.com/platform/frameworks/volley

然后编译为jar包,再把jar包放到自己的工程的libs目录。

2.使用请求队列

Volley的所有请求都放在一个队列,然后进行处理,这里是你如何将创建一个请求队列:

  1. RequestQueue mRequestQueue = Volley.newRequestQueue(this); // 'this' is Context

理想的情况是把请求队列集中放到一个地方,最好是初始化应用程序类中初始化请求队列,下面类做到了这一点:

  1. public class ApplicationController extends Application {
  2.  
  3. /**
  4. * Log or request TAG
  5. */
  6. public static final String TAG = "VolleyPatterns";
  7.  
  8. /**
  9. * Global request queue for Volley
  10. */
  11. private RequestQueue mRequestQueue;
  12.  
  13. /**
  14. * A singleton instance of the application class for easy access in other places
  15. */
  16. private static ApplicationController sInstance;
  17.  
  18. @Override
  19. public void onCreate() {
  20. super.onCreate();
  21.  
  22. // initialize the singleton
  23. sInstance = this;
  24. }
  25.  
  26. /**
  27. * @return ApplicationController singleton instance
  28. */
  29. public static synchronized ApplicationController getInstance() {
  30. return sInstance;
  31. }
  32.  
  33. /**
  34. * @return The Volley Request queue, the queue will be created if it is null
  35. */
  36. public RequestQueue getRequestQueue() {
  37. // lazy initialize the request queue, the queue instance will be
  38. // created when it is accessed for the first time
  39. if (mRequestQueue == null) {
  40. mRequestQueue = Volley.newRequestQueue(getApplicationContext());
  41. }
  42.  
  43. return mRequestQueue;
  44. }
  45.  
  46. /**
  47. * Adds the specified request to the global queue, if tag is specified
  48. * then it is used else Default TAG is used.
  49. *
  50. * @param req
  51. * @param tag
  52. */
  53. public <T> void addToRequestQueue(Request<T> req, String tag) {
  54. // set the default tag if tag is empty
  55. req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
  56.  
  57. VolleyLog.d("Adding request to queue: %s", req.getUrl());
  58.  
  59. getRequestQueue().add(req);
  60. }
  61.  
  62. /**
  63. * Adds the specified request to the global queue using the Default TAG.
  64. *
  65. * @param req
  66. * @param tag
  67. */
  68. public <T> void addToRequestQueue(Request<T> req) {
  69. // set the default tag if tag is empty
  70. req.setTag(TAG);
  71.  
  72. getRequestQueue().add(req);
  73. }
  74.  
  75. /**
  76. * Cancels all pending requests by the specified TAG, it is important
  77. * to specify a TAG so that the pending/ongoing requests can be cancelled.
  78. *
  79. * @param tag
  80. */
  81. public void cancelPendingRequests(Object tag) {
  82. if (mRequestQueue != null) {
  83. mRequestQueue.cancelAll(tag);
  84. }
  85. }
  86. }

3.异步的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请求:

  1. final String URL = "/volley/resource/12";
  2. // pass second argument as "null" for GET requests
  3. JsonObjectRequest req = new JsonObjectRequest(URL, null,
  4. new Response.Listener<JSONObject>() {
  5. @Override
  6. public void onResponse(JSONObject response) {
  7. try {
  8. VolleyLog.v("Response:%n %s", response.toString(4));
  9. } catch (JSONException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }, new Response.ErrorListener() {
  14. @Override
  15. public void onErrorResponse(VolleyError error) {
  16. VolleyLog.e("Error: ", error.getMessage());
  17. }
  18. });
  19.  
  20. // add the request object to the queue to be executed
  21. ApplicationController.getInstance().addToRequestQueue(req);

POST请求:

  1. final String URL = "/volley/resource/12";
  2. // Post params to be sent to the server
  3. HashMap<String, String> params = new HashMap<String, String>();
  4. params.put("token", "AbCdEfGh123456");
  5.  
  6. JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params),
  7. new Response.Listener<JSONObject>() {
  8. @Override
  9. public void onResponse(JSONObject response) {
  10. try {
  11. VolleyLog.v("Response:%n %s", response.toString(4));
  12. } catch (JSONException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. }, new Response.ErrorListener() {
  17. @Override
  18. public void onErrorResponse(VolleyError error) {
  19. VolleyLog.e("Error: ", error.getMessage());
  20. }
  21. });
  22.  
  23. // add the request object to the queue to be executed
  24. ApplicationController.getInstance().addToRequestQueue(req);

JsonArrayRequest

这个类可以用来接受 JSON Arrary,不支持JSON Object。这个类现在只支持 HTTP GET。由于支持GET,你可以在URL的后面加上请求参数。类的构造函数不支持请求参数

  1. final String URL = "/volley/resource/all?count=20";
  2. JsonArrayRequest req = new JsonArrayRequest(URL, new Response.Listener<JSONArray> () {
  3. @Override
  4. public void onResponse(JSONArray response) {
  5. try {
  6. VolleyLog.v("Response:%n %s", response.toString(4));
  7. } catch (JSONException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }, new Response.ErrorListener() {
  12. @Override
  13. public void onErrorResponse(VolleyError error) {
  14. VolleyLog.e("Error: ", error.getMessage());
  15. }
  16. });
  17.  
  18. // add the request object to the queue to be executed
  19. ApplicationController.getInstance().addToRequestQueue(req);

StringRequest

这个类可以用来从服务器获取String,如果想自己解析请求响应可以使用这个类,例如返回xml数据。它还可以使用重载的构造函数定制请求

  1. final String URL = "/volley/resource/recent.xml";
  2. StringRequest req = new StringRequest(URL, new Response.Listener<String>() {
  3. @Override
  4. public void onResponse(String response) {
  5. VolleyLog.v("Response:%n %s", response);
  6. }
  7. }, new Response.ErrorListener() {
  8. @Override
  9. public void onErrorResponse(VolleyError error) {
  10. VolleyLog.e("Error: ", error.getMessage());
  11. }
  12. });
  13.  
  14. // add the request object to the queue to be executed
  15. ApplicationController.getInstance().addToRequestQueue(req);

4.取消请求

Volley提供了强大的API取消未处理或正在处理的请求。取消请求最简单的方法是调用请求队列cancelAll(tag)的方法,前提是你在添加请求时设置了标记。这样就能使标签标记的请求挂起。

给请求设置标签:

  1. request.setTag("My Tag");

使用ApplicationController添加使用了标签的请求到队列中:

  1. ApplicationController.getInstance().addToRequestQueue(request, "My Tag");

取消所有指定标记的请求:

  1. mRequestQueue.cancelAll("My Tag");

5.重试失败的请求,自定义请求超时

Volley中没有指定的方法来设置请求超时时间,可以设置RetryPolicy 来变通实现。DefaultRetryPolicy类有个initialTimeout参数,可以设置超时时间。要确保最大重试次数为1,以保证超时后不重新请求。

Setting Request Timeout

request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));

设置请求头(HTTP headers)        如果你想失败后重新请求(因超时),您可以指定使用上面的代码,增加重试次数。注意最后一个参数,它允许你指定一个退避乘数可以用来实现“指数退避”来从RESTful服务器请求数据。

有时候需要给HTTP请求添加额外的头信息,一个常用的例子是添加 “Authorization”到HTTP 请求的头信息。Volley请求类提供了一个 getHeaers()的方法,重载这个方法可以自定义HTTP 的头信息。

添加头信息:

  1. JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params),
  2. new Response.Listener<JSONObject>() {
  3. @Override
  4. public void onResponse(JSONObject response) {
  5. // handle response
  6. }
  7. }, new Response.ErrorListener() {
  8. @Override
  9. public void onErrorResponse(VolleyError error) {
  10. // handle error
  11. }
  12. }) {
  13.  
  14. @Override
  15. public Map<String, String> getHeaders() throws AuthFailureError {
  16. HashMap<String, String> headers = new HashMap<String, String>();
  17. headers.put("CUSTOM_HEADER", "Yahoo");
  18. headers.put("ANOTHER_CUSTOM_HEADER", "Google");
  19. return headers;
  20. }
  21. };

6.使用Cookies

Volley中没有直接的API来设置cookies,Volley的设计理念就是提供干净、简洁的API来实现RESTful HTTP请求,不提供设置cookies是合理的。

下面是修改后的ApplicationController类,这个类修改了getRequestQueue()方法,包含了 设置cookie方法,这些修改还是有些粗糙

  1. // http client instance
  2. private DefaultHttpClient mHttpClient;
  3. public RequestQueue getRequestQueue() {
  4. // lazy initialize the request queue, the queue instance will be
  5. // created when it is accessed for the first time
  6. if (mRequestQueue == null) {
  7. // Create an instance of the Http client.
  8. // We need this in order to access the cookie store
  9. mHttpClient = new DefaultHttpClient();
  10. // create the request queue
  11. mRequestQueue = Volley.newRequestQueue(this, new HttpClientStack(mHttpClient));
  12. }
  13. return mRequestQueue;
  14. }
  15.  
  16. /**
  17. * Method to set a cookie
  18. */
  19. public void setCookie() {
  20. CookieStore cs = mHttpClient.getCookieStore();
  21. // create a cookie
  22. cs.addCookie(new BasicClientCookie2("cookie", "spooky"));
  23. }
  24.  
  25. // add the cookie before adding the request to the queue
  26. setCookie();
  27.  
  28. // add the request to the queue
  29. mRequestQueue.add(request);

7.错误处理

正如前面代码看到的,在创建一个请求时,需要添加一个错误监听onErrorResponse。如果请求发生异常,会返回一个VolleyError实例。

以下是Volley的异常列表:

AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。

NetworkError:Socket关闭,服务器宕机,DNS错误都会产生这个错误。

NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。

ParseError:在使用JsonObjectRequest或JsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。

SERVERERROR:服务器的响应的一个错误,最有可能的4xx或5xx HTTP状态代码。

TimeoutError:Socket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy。

可以使用一个简单的Help类根据这些异常提示相应的信息:

  1. public class VolleyErrorHelper {
  2. /**
  3. * Returns appropriate message which is to be displayed to the user
  4. * against the specified error object.
  5. *
  6. * @param error
  7. * @param context
  8. * @return
  9. */
  10. public static String getMessage(Object error, Context context) {
  11. if (error instanceof TimeoutError) {
  12. return context.getResources().getString(R.string.generic_server_down);
  13. }
  14. else if (isServerProblem(error)) {
  15. return handleServerError(error, context);
  16. }
  17. else if (isNetworkProblem(error)) {
  18. return context.getResources().getString(R.string.no_internet);
  19. }
  20. return context.getResources().getString(R.string.generic_error);
  21. }
  22.  
  23. /**
  24. * Determines whether the error is related to network
  25. * @param error
  26. * @return
  27. */
  28. private static boolean isNetworkProblem(Object error) {
  29. return (error instanceof NetworkError) || (error instanceof NoConnectionError);
  30. }
  31. /**
  32. * Determines whether the error is related to server
  33. * @param error
  34. * @return
  35. */
  36. private static boolean isServerProblem(Object error) {
  37. return (error instanceof ServerError) || (error instanceof AuthFailureError);
  38. }
  39. /**
  40. * Handles the server error, tries to determine whether to show a stock message or to
  41. * show a message retrieved from the server.
  42. *
  43. * @param err
  44. * @param context
  45. * @return
  46. */
  47. private static String handleServerError(Object err, Context context) {
  48. VolleyError error = (VolleyError) err;
  49.  
  50. NetworkResponse response = error.networkResponse;
  51.  
  52. if (response != null) {
  53. switch (response.statusCode) {
  54. case 404:
  55. case 422:
  56. case 401:
  57. try {
  58. // server might return error like this { "error": "Some error occured" }
  59. // Use "Gson" to parse the result
  60. HashMap<String, String> result = new Gson().fromJson(new String(response.data),
  61. new TypeToken<Map<String, String>>() {
  62. }.getType());
  63.  
  64. if (result != null && result.containsKey("error")) {
  65. return result.get("error");
  66. }
  67.  
  68. } catch (Exception e) {
  69. e.printStackTrace();
  70. }
  71. // invalid request
  72. return error.getMessage();
  73.  
  74. default:
  75. return context.getResources().getString(R.string.generic_server_down);
  76. }
  77. }
  78. return context.getResources().getString(R.string.generic_error);
  79. }
  80. }

总结:

Volley是一个非常好的库,你可以尝试使用一下,它会帮助你简化网络请求,带来更多的益处。

我也希望更加全面的介绍Volley,以后可能会介绍使用volley加载图像的内容,欢迎关注

【开源项目13】Volley框架 以及 设置request超时时间的更多相关文章

  1. Mybatis设置sql超时时间

    开始搭建项目框架的时候,忽略了sql执行超时时间的问题. 原本使用.net开发是,默认的超时时间是30s,这个时间一般一般sql是用不到的,但也不排除一些比较复杂或数据量较大的sql. 而java中, ...

  2. WebLogic如何设置session超时时间

    1.web.xml  设置WEB应用程序描述符web.xml里的<session-timeout>元素.这个值以分钟为单位,并覆盖weblogic.xml中的TimeoutSecs属性   ...

  3. C# 的tcp Socket设置自定义超时时间

    简单的c# TCP通讯(TcpListener) C# 的TCP Socket (同步方式) C# 的TCP Socket (异步方式) C# 的tcp Socket设置自定义超时时间 C# TCP ...

  4. 转 HttpClient 设置连接超时时间

    要: HttpClient 4.5版本升级后,设置超时时间的API又有新的变化,请大家关注. HttpClient升级到4.5版本后,API有很多变化,HttpClient 4之后,API一直没有太稳 ...

  5. HttpClient设置连接超时时间

    https://www.cnblogs.com/winner-0715/p/7087591.html 使用HttpClient,一般都需要设置连接超时时间和获取数据超时时间.这两个参数很重要,目的是为 ...

  6. WebSphere设置会话超时时间

    WebSphere Application Server的会话超时时间可以在三个层面进行设置,分别为:应用程序服务器级别.应用程序级别和代码层面进行设置. 设置方式:应用程序级别级别和应用级别可以通过 ...

  7. 【轮询】【ajax】【js】【spring boot】ajax超时请求:前端轮询处理超时请求解决方案 + spring boot服务设置接口超时时间的设置

    场景描述: ajax设置timeout在本机测试有效,但是在生产环境等外网环境无效的问题 1.ajax的timeout属性设置 前端请求超时事件[网络连接不稳定时候,就无效了] var data = ...

  8. integrator.setTimeout 设置一个超时时间,超过这个时间之后,扫描的 Activity 将会被 finish 。

    integrator.setTimeout 设置一个超时时间,超过这个时间之后,扫描的 Activity 将会被 finish . +++++++++++++++++++ 经查,没有这个功能

  9. subprocess如何设置命令超时时间

    一.subprocess如何设置命令超时时间 最近遇到一个问题,就是我需要在服务器上执行某些shell命令,但是有些命令失败的时候是不会自动终止的,只会一直停在那里,很耗时间. 因此想到了设置超时时间 ...

随机推荐

  1. PCB板简易流程

    PCB布线规则设置 在进行布线之前一般要进行布线规则的设置,(因为元器件的封装已经画出了元件实际的轮廓大小,所以放置元件封装时,即使两个元件封装挨着也一般不会影响元件的实际安装,不过一般还是稍留一点距 ...

  2. centos 安装redis php

    $ wget http://download.redis.io/releases/redis-3.0.7.tar.gz $ tar xzf redis-3.0.7.tar.gz $ cd redis- ...

  3. CStdioFile

    CStdioFile类的声明保存再afx.h头文件中. CStdioFile类继承自CFile类,CStdioFile对象表示一个用运行时的函数fopen打开的c运行时的流式文件.流式文件是被缓冲的, ...

  4. 关于 ServiceStack.Redis 4.0 License

    今天更新了框架中的Redis驱动ServiceStack.Redis,最新版本4.0.5.0. 在做简单压力测试时出现异常,提示每小时允许6000个请求. The free-quota limit o ...

  5. js关闭当前页面/关闭当前窗口

    function CloseWebPage(){ if (navigator.userAgent.indexOf("MSIE") > 0) {  if (navigator. ...

  6. 初步认识shell

    言语不多说,直奔主题,lz不善于写文章,只是记录自己学习过程中的点点滴滴. 注意:shell对于字母大小写比较敏感. 打开终端出现:username@hostname$或者root@hostname# ...

  7. 解决NDK开发中Eclipse报错“Unresolved inclusion jni.h”的最终方法

    http://blog.csdn.net/zhubin215130/article/details/39347873

  8. 闲话Cache:始篇

    Caching(缓存)在现代的计算机系统中是一项最古老最基本的技术.它存在于计算机各种硬件和软件系统中,比如各种CPU, 存储系统(IBM ESS, EMC Symmetrix…),数据库,Web服务 ...

  9. 真正通用的SQL分页存储过程

    关于SQL分页的问题,网上找到的一些SQL其实不能真正做到通用,他们主要是以自增长ID做为前提的.但在实际使用中,很多表不是自增长的,而且主键也不止一个字段,其实我们稍做改进就可以达到通用.这里还增加 ...

  10. 以Outlook样式分组和排列数据项

    转载:http://www.cnblogs.com/peterzb/archive/2009/05/29/1491781.html OutlookGrid:以Outlook样式分组和排列数据项 (这里 ...