ym—— Android網路架構Volley(實戰篇),androidvolley
之前講了ym—— Android網路架構Volley(體驗篇),大家應該瞭解了volley的使用,接下來我們要看看如何把volley使用到實戰項目裡面,我們先考慮下一些問題:
從上一篇來看 mQueue 只需要一個對象即可,new RequestQueue對象對資源一種浪費,我們應該在application,以及可以把取消請求的方法也在application進行統一管理,看以下代碼:
package com.chronocloud.lib.base;import android.app.Application;import android.text.TextUtils;import com.android.volley.Request;import com.android.volley.RequestQueue;import com.android.volley.VolleyLog;import com.android.volley.toolbox.Volley;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;@Overridepublic void onCreate() {super.onCreate();// initialize the singletonsInstance = 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 timeif (mRequestQueue == null) {// 1// 2synchronized (ApplicationController.class) {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 emptyreq.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 emptyreq.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);}}}接下來就是Volley雖然給我們提供了很多不同的Request(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest),但是還是滿足不了我們實戰中的需求,我們實戰開發中經常用到的是xml格式,Gson解析。
接下來我們來看看,如何自訂Request
XmlRequest:
public class XMLRequest extends Request<XmlPullParser> {private final Listener<XmlPullParser> mListener;public XMLRequest(int method, String url, Listener<XmlPullParser> listener,ErrorListener errorListener) {super(method, url, errorListener);mListener = listener;}public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {this(Method.GET, url, listener, errorListener);}@Overrideprotected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {try {String xmlString = new String(response.data,HttpHeaderParser.parseCharset(response.headers));XmlPullParserFactory factory = XmlPullParserFactory.newInstance();XmlPullParser xmlPullParser = factory.newPullParser();xmlPullParser.setInput(new StringReader(xmlString));return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));} catch (UnsupportedEncodingException e) {return Response.error(new ParseError(e));} catch (XmlPullParserException e) {return Response.error(new ParseError(e));}}@Overrideprotected void deliverResponse(XmlPullParser response) {mListener.onResponse(response);}}
GsonRequest(注意需要自行匯入gson.jar):
public class GsonRequest<T> extends Request<T> {private final Listener<T> mListener;private Gson mGson;private Class<T> mClass;public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,ErrorListener errorListener) {super(method, url, errorListener);mGson = new Gson();mClass = clazz;mListener = listener;}public GsonRequest(String url, Class<T> clazz, Listener<T> listener,ErrorListener errorListener) {this(Method.GET, url, clazz, listener, errorListener);}@Overrideprotected Response<T> parseNetworkResponse(NetworkResponse response) {try {String jsonString = new String(response.data,HttpHeaderParser.parseCharset(response.headers));return Response.success(mGson.fromJson(jsonString, mClass),HttpHeaderParser.parseCacheHeaders(response));} catch (UnsupportedEncodingException e) {return Response.error(new ParseError(e));}}@Overrideprotected void deliverResponse(T response) {mListener.onResponse(response);}}接下只差最後一步了就是封裝它的錯誤處理,使用過volley的都知道,volley的監聽錯誤提示都是NoConnectionError。。。等等,這類的錯誤提示,顯然這不是我們想給使用者呈現的錯誤提示,因為就算提示了使用者也不明白什麼意思,所以我們還要封裝一下,能讓使用者看的更清楚的理解這些錯誤提示。ym—— Android網路架構Volley(體驗篇)我們講過每個請求都需要設定一個失敗的監聽:
// 共用失敗回調private class StrErrListener implements ErrorListener {@Overridepublic void onErrorResponse(VolleyError arg0) {Toast.makeText(mContext,VolleyErrorHelper.getMessage(arg0, mContext),Toast.LENGTH_LONG).show();}}以上代碼有個VolleyError對象,我們可以從這個對象上下手:
package com.example.volley;import java.util.HashMap;import java.util.Map;import android.content.Context;import com.android.volley.AuthFailureError;import com.android.volley.NetworkError;import com.android.volley.NetworkResponse;import com.android.volley.NoConnectionError;import com.android.volley.ServerError;import com.android.volley.TimeoutError;import com.android.volley.VolleyError;import com.google.gson.Gson;import com.google.gson.reflect.TypeToken;//正如前面代碼看到的,在建立一個請求時,需要添加一個錯誤監聽onErrorResponse。如果請求發生異常,會返回一個VolleyError執行個體。//以下是Volley的異常列表://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 resultHashMap<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 requestreturn error.getMessage();default:return context.getResources().getString(R.string.generic_server_down);}}return context.getResources().getString(R.string.generic_error);}}
以上代碼中引用的xml是:
<string name="no_internet">無網路連接~!</string><string name="generic_server_down">串連伺服器失敗~!</string><string name="generic_error">網路異常,請稍後再試~!</string>
接下來,資料請求這一塊已經說完了,我們來說片這一塊,我個人喜歡使用universal-image-loader而不是volley自己提供的(個人認為使用起來universal-image-loader更便捷一些)。好啦講完了,大家可以去實戰開發了~!不懂或者遇到問題的可以留言討論~!
Android的Volley架構可以否用在與WebService的通訊上?
不能,你也是知道的 velloy使用的是http協議。而webservice使用的是soap。兩個不同的通訊機制
android開發架構
json解析可以用google的gson包.
網路請求和緩衝機制(一般是指圖片緩衝吧)可以看看volley.
資料庫比較簡單,android內建的已經算是封裝過了.不過你可以看看Afinal裡面的FinalDb.
UI方面就沒有了.都是自己寫的.掌握好view和viewgroup.基本上所有控制項就掌握了.