Android网络框架Volley(实战篇)

之前讲了ym—— Android网络框架Volley(体验篇),大家应该了解了volley的使用,接下来我们要看看如何把volley使用到实战项目里面,我们先考虑下一些问题:

从上一篇来看 mQueue 只需要一个对象即可,new RequestQueue对象对资源一种浪费,我们应该在application,以及可以把取消请求的方法也在application进行统一管理,看以下代码:

  1. package com.chronocloud.lib.base;  
  2.   
  3. import android.app.Application;  
  4. import android.text.TextUtils;  
  5.   
  6. import com.android.volley.Request;  
  7. import com.android.volley.RequestQueue;  
  8. import com.android.volley.VolleyLog;  
  9. import com.android.volley.toolbox.Volley;  
  10.   
  11. public class ApplicationController extends Application {  
  12.   
  13.     /** 
  14.      * Log or request TAG 
  15.      */  
  16.     public static final String TAG = "VolleyPatterns";  
  17.   
  18.     /** 
  19.      * Global request queue for Volley 
  20.      */  
  21.     private RequestQueue mRequestQueue;  
  22.   
  23.     /** 
  24.      * A singleton instance of the application class for easy access in other 
  25.      * places 
  26.      */  
  27.     private static ApplicationController sInstance;  
  28.   
  29.     @Override  
  30.     public void onCreate() {  
  31.         super.onCreate();  
  32.   
  33.         // initialize the singleton  
  34.         sInstance = this;  
  35.     }  
  36.   
  37.     /** 
  38.      * @return ApplicationController singleton instance 
  39.      */  
  40.     public static synchronized ApplicationController getInstance() {  
  41.         return sInstance;  
  42.     }  
  43.   
  44.     /** 
  45.      * @return The Volley Request queue, the queue will be created if it is null 
  46.      */  
  47.     public RequestQueue getRequestQueue() {  
  48.         // lazy initialize the request queue, the queue instance will be  
  49.         // created when it is accessed for the first time  
  50.         if (mRequestQueue == null) {  
  51.             // 1  
  52.             // 2  
  53.             synchronized (ApplicationController.class) {  
  54.                 if (mRequestQueue == null) {  
  55.                     mRequestQueue = Volley  
  56.                             .newRequestQueue(getApplicationContext());  
  57.                 }  
  58.             }  
  59.         }  
  60.         return mRequestQueue;  
  61.     }  
  62.   
  63.     /** 
  64.      * Adds the specified request to the global queue, if tag is specified then 
  65.      * it is used else Default TAG is used. 
  66.      *  
  67.      * @param req 
  68.      * @param tag 
  69.      */  
  70.     public <T> void addToRequestQueue(Request<T> req, String tag) {  
  71.         // set the default tag if tag is empty  
  72.         req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);  
  73.   
  74.         VolleyLog.d("Adding request to queue: %s", req.getUrl());  
  75.   
  76.         getRequestQueue().add(req);  
  77.     }  
  78.   
  79.     /** 
  80.      * Adds the specified request to the global queue using the Default TAG. 
  81.      *  
  82.      * @param req 
  83.      * @param tag 
  84.      */  
  85.     public <T> void addToRequestQueue(Request<T> req) {  
  86.         // set the default tag if tag is empty  
  87.         req.setTag(TAG);  
  88.   
  89.         getRequestQueue().add(req);  
  90.     }  
  91.   
  92.     /** 
  93.      * Cancels all pending requests by the specified TAG, it is important to 
  94.      * specify a TAG so that the pending/ongoing requests can be cancelled. 
  95.      *  
  96.      * @param tag 
  97.      */  
  98.     public void cancelPendingRequests(Object tag) {  
  99.         if (mRequestQueue != null) {  
  100.             mRequestQueue.cancelAll(tag);  
  101.         }  
  102.     }  
  103. }  
接下来 就是Volley虽然给我们提供了很多不同的Request(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest),但是还是满足不了我们实战中的需求,我们实战开发中经常用到的是xml格式,Gson解析。

接下来我们来看看,如何自定义Request

XmlRequest:

  1. public class XMLRequest extends Request<XmlPullParser> {  
  2.   
  3.     private final Listener<XmlPullParser> mListener;  
  4.   
  5.     public XMLRequest(int method, String url, Listener<XmlPullParser> listener,  
  6.             ErrorListener errorListener) {  
  7.         super(method, url, errorListener);  
  8.         mListener = listener;  
  9.     }  
  10.   
  11.     public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {  
  12.         this(Method.GET, url, listener, errorListener);  
  13.     }  
  14.   
  15.     @Override  
  16.     protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {  
  17.         try {  
  18.             String xmlString = new String(response.data,  
  19.                     HttpHeaderParser.parseCharset(response.headers));  
  20.             XmlPullParserFactory factory = XmlPullParserFactory.newInstance();  
  21.             XmlPullParser xmlPullParser = factory.newPullParser();  
  22.             xmlPullParser.setInput(new StringReader(xmlString));  
  23.             return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));  
  24.         } catch (UnsupportedEncodingException e) {  
  25.             return Response.error(new ParseError(e));  
  26.         } catch (XmlPullParserException e) {  
  27.             return Response.error(new ParseError(e));  
  28.         }  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void deliverResponse(XmlPullParser response) {  
  33.         mListener.onResponse(response);  
  34.     }  
  35.   
  36. }  

GsonRequest(注意需要自行导入gson.jar):

  1. public class GsonRequest<T> extends Request<T> {  
  2.   
  3.     private final Listener<T> mListener;  
  4.   
  5.     private Gson mGson;  
  6.   
  7.     private Class<T> mClass;  
  8.   
  9.     public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,  
  10.             ErrorListener errorListener) {  
  11.         super(method, url, errorListener);  
  12.         mGson = new Gson();  
  13.         mClass = clazz;  
  14.         mListener = listener;  
  15.     }  
  16.   
  17.     public GsonRequest(String url, Class<T> clazz, Listener<T> listener,  
  18.             ErrorListener errorListener) {  
  19.         this(Method.GET, url, clazz, listener, errorListener);  
  20.     }  
  21.   
  22.     @Override  
  23.     protected Response<T> parseNetworkResponse(NetworkResponse response) {  
  24.         try {  
  25.             String jsonString = new String(response.data,  
  26.                     HttpHeaderParser.parseCharset(response.headers));  
  27.             return Response.success(mGson.fromJson(jsonString, mClass),  
  28.                     HttpHeaderParser.parseCacheHeaders(response));  
  29.         } catch (UnsupportedEncodingException e) {  
  30.             return Response.error(new ParseError(e));  
  31.         }  
  32.     }  
  33.   
  34.     @Override  
  35.     protected void deliverResponse(T response) {  
  36.         mListener.onResponse(response);  
  37.     }  
  38.   
  39. }  
接下只差最后一步了就是封装它的错误处理,使用过volley的都知道,volley的监听错误提示都是NoConnectionError。。。等等,这类的错误提示,显然这不是我们想给用户呈现的错误提示,因为就算提示了用户也不明白什么意思,所以我们还要封装一下,能让用户看的更清楚的理解这些错误提示。ym—— Android网络框架Volley(体验篇)我们讲过每个请求都需要设置一个失败的监听:

  1. // 共用失败回调  
  2. private class StrErrListener implements ErrorListener {  
  3.   
  4.     @Override  
  5.     public void onErrorResponse(VolleyError arg0) {  
  6.         Toast.makeText(mContext,  
  7.                 VolleyErrorHelper.getMessage(arg0, mContext),  
  8.                 Toast.LENGTH_LONG).show();  
  9.     }  
  10.   
  11. }  
以上代码有个VolleyError对象,我们可以从这个对象上下手:

  1. package com.example.volley;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import android.content.Context;  
  7.   
  8. import com.android.volley.AuthFailureError;  
  9. import com.android.volley.NetworkError;  
  10. import com.android.volley.NetworkResponse;  
  11. import com.android.volley.NoConnectionError;  
  12. import com.android.volley.ServerError;  
  13. import com.android.volley.TimeoutError;  
  14. import com.android.volley.VolleyError;  
  15. import com.google.gson.Gson;  
  16. import com.google.gson.reflect.TypeToken;  
  17. //正如前面代码看到的,在创建一个请求时,需要添加一个错误监听onErrorResponse。如果请求发生异常,会返回一个VolleyError实例。  
  18. //以下是Volley的异常列表:  
  19. //AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。  
  20. //NetworkError:Socket关闭,服务器宕机,DNS错误都会产生这个错误。  
  21. //NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。  
  22. //ParseError:在使用JsonObjectRequest或JsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。  
  23. //SERVERERROR:服务器的响应的一个错误,最有可能的4xx或5xx HTTP状态代码。  
  24. //TimeoutError:Socket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy。  
  25.   
  26. public class VolleyErrorHelper {  
  27.   
  28.     /** 
  29.      * Returns appropriate message which is to be displayed to the user against 
  30.      * the specified error object. 
  31.      *  
  32.      * @param error 
  33.      * @param context 
  34.      * @return 
  35.      */  
  36.     public static String getMessage(Object error, Context context) {  
  37.         if (error instanceof TimeoutError) {  
  38.             return context.getResources().getString(  
  39.                     R.string.generic_server_down);  
  40.         } else if (isServerProblem(error)) {  
  41.             return handleServerError(error, context);  
  42.         } else if (isNetworkProblem(error)) {  
  43.             return context.getResources().getString(R.string.no_internet);  
  44.         }  
  45.         return context.getResources().getString(R.string.generic_error);  
  46.     }  
  47.   
  48.     /** 
  49.      * Determines whether the error is related to network 
  50.      *  
  51.      * @param error 
  52.      * @return 
  53.      */  
  54.     private static boolean isNetworkProblem(Object error) {  
  55.         return (error instanceof NetworkError)  
  56.                 || (error instanceof NoConnectionError);  
  57.     }  
  58.   
  59.     /** 
  60.      * Determines whether the error is related to server 
  61.      *  
  62.      * @param error 
  63.      * @return 
  64.      */  
  65.     private static boolean isServerProblem(Object error) {  
  66.         return (error instanceof ServerError)  
  67.                 || (error instanceof AuthFailureError);  
  68.     }  
  69.   
  70.     /** 
  71.      * Handles the server error, tries to determine whether to show a stock 
  72.      * message or to show a message retrieved from the server. 
  73.      *  
  74.      * @param err 
  75.      * @param context 
  76.      * @return 
  77.      */  
  78.     private static String handleServerError(Object err, Context context) {  
  79.         VolleyError error = (VolleyError) err;  
  80.   
  81.         NetworkResponse response = error.networkResponse;  
  82.   
  83.         if (response != null) {  
  84.             switch (response.statusCode) {  
  85.             case 404:  
  86.             case 422:  
  87.             case 401:  
  88.                 try {  
  89.                     // server might return error like this { "error":  
  90.                     // "Some error occured" }  
  91.                     // Use "Gson" to parse the result  
  92.                     HashMap<String, String> result = new Gson().fromJson(  
  93.                             new String(response.data),  
  94.                             new TypeToken<Map<String, String>>() {  
  95.                             }.getType());  
  96.   
  97.                     if (result != null && result.containsKey("error")) {  
  98.                         return result.get("error");  
  99.                     }  
  100.   
  101.                 } catch (Exception e) {  
  102.                     e.printStackTrace();  
  103.                 }  
  104.                 // invalid request  
  105.                 return error.getMessage();  
  106.   
  107.             default:  
  108.                 return context.getResources().getString(  
  109.                         R.string.generic_server_down);  
  110.             }  
  111.         }  
  112.         return context.getResources().getString(R.string.generic_error);  
  113.     }  
  114. }  

以上代码中引用的xml是:

  1. <string name="no_internet">无网络连接~!</string>  
  2. <string name="generic_server_down">连接服务器失败~!</string>  
  3. <string name="generic_error">网络异常,请稍后再试~!</string>  
接下来,数据请求这一块已经说完了,我们来说下图片这一块,我个人喜欢使用universal-image-loader而不是volley自己提供的(个人认为使用起来 universal-image-loader更便捷一些)。好啦讲完了,大家可以去实战开发了~!不懂或者遇到问题的可以留言讨论~!
  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值