Asynchronous HTTP Requests in Android Using Volley



http://blog.csdn.net/xyz_lmn/article/details/12177005   http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/     目录(?)[-]

  1. Volley提供的功能
  2. 为什么使用异步HTTP请求
  3. 怎样使用Volley
    1. 安装和使用Volley库
    2. 使用请求队列
    3. 异步的JSONString请求
      1. JsonObjectRequest
      2. JsonArrayRequest
      3. StringRequest
    4. 取消请求
    5. 重试失败的请求自定义请求超时
    6. 设置请求头HTTP headers
    7. 使用Cookies
    8. 错误处理
  4. 总结

   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库先克隆一个下来:

[plain]  view plain copy print ?
  1. git clone https://android.googlesource.com/platform/frameworks/volley  

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

使用请求队列

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

[java]  view plain copy print ?
  1. RequestQueue mRequestQueue = Volley.newRequestQueue(this); // 'this' is Context  

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

[java]  view plain copy print ?
  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. }  


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

[java]  view plain copy print ?
  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请求:

[java]  view plain copy print ?
  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的后面加上请求参数。类的构造函数不支持请求参数。


[java]  view plain copy print ?
  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数据。它还可以使用重载的构造函数定制请求。

[java]  view plain copy print ?
  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);  


取消请求

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


给请求设置标签:

[java]  view plain copy print ?
  1. request.setTag("My Tag");  

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

[java]  view plain copy print ?
  1. ApplicationController.getInstance().addToRequestQueue(request, "My Tag");  

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

[java]  view plain copy print ?
  1. mRequestQueue.cancelAll("My Tag");  


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

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


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

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


设置请求头(HTTP headers)

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


添加头信息:

[java]  view plain copy print ?
  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.    };  


使用Cookies

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


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


[java]  view plain copy print ?
  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(thisnew 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.   
  26. // add the cookie before adding the request to the queue  
  27. setCookie();  
  28.   
  29. // add the request to the queue  
  30. mRequestQueue.add(request);  



错误处理

       正如前面代码看到的,在创建一个请求时,需要添加一个错误监听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类根据这些异常提示相应的信息:
[java]  view plain copy print ?
  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加载图像的内容,欢迎关注。

        谢谢你的阅读,希望你能喜欢。


参考:


/**
* @author 张兴业
*  iOS入门群:83702688
*  android开发进阶群:241395671
*  我的新浪微博:@张兴业TBOW
*/


原文:

http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值