我們已經講了ImageRequest、StringRequest等等的用法 今天我就來自定義一個Request 我們可以讓我們的請求傳回泛型的資料、然後我們根據需要去解析相應的資料
好 首先我們先來看一下 StringR equest的源碼
- public class StringRequest extends Request<String> {
- private final Listener<String> mListener;
- public StringRequest(int method, String url, Listener<String> listener,
- ErrorListener errorListener) {
- super(method, url, errorListener);
- mListener = listener;
- }
- public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
- this(Method.GET, url, listener, errorListener);
- }
- @Override
- protected void deliverResponse(String response) {
- mListener.onResponse(response);
- }
- @Override
- protected Response<String> parseNetworkResponse(NetworkResponse response) {
- String parsed;
- try {
- parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
- } catch (UnsupportedEncodingException e) {
- parsed = new String(response.data);
- }
- return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
- }
- }
我們看到這個源碼很簡單 首先我們的StringRequest繼承了Request 這裡的 Request我們可以指定泛型的 我們在這裡指定的是String類型的 接下來我們看到兩個帶有參數的構造方法 在構造函數中一定要調用Super() 講一些參數傳給父類 因為請求、相應都是在父類中自動進行的
接下來的兩個方法parseNetworkResponse deliverResponse 因為這兩個方法在Request中都是抽象的 我們必須實作這兩個方法 deliverResponse 這個方法很簡單 隻是調用了 mListener.onResponse(response); 這樣我們就可以将伺服器傳回的資料進行回調了 parseNetworkResponse是對伺服器響應的資料進行解析,其中資料是以位元組的形式存放在NetworkResponse的data變量中的,這裡将資料取出然後組裝成一個String,并傳入Response的success()方法中即可 HttpHeaderParser.parseCharset(response.headers)其實就是擷取我們的傳回流的編碼,也就是我上面伺服器設定的utf-8 好了 這樣我們就把StringRequest的源碼看完了 是不是感覺很簡單 接下來我們就自定義一個Request
我們知道谷歌官方推出了Gson 咱們就用這個Gson解析咱們伺服器傳回的資料 然後咱們自定義一個GsonRequest 看代碼
public class GsonRequest<T> extends Request<T> {
private static final String PROTOCOL_CHARSET = "utf-8";
private static final String PROTOCOL_CONTENT_TYPE = String.format(
"application/json; charset=%s", PROTOCOL_CHARSET);
private Gson mGson;
// 上下文
private Context context;
// 監聽器
private Listener<T> mListener;
// 泛型類(解析的Bean類型)
private Class<T> mClass;
// 上傳的參數
private String mRequestBody;
private Map<String, String> params = new HashMap<String, String>();
private Map<String, String> headers = new HashMap<String, String>();
private int timeOut = 35000;
public GsonRequest(int method, String url, String mRequestBody,
Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mRequestBody = mRequestBody;
this.mListener = listener;
}
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
}
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener,
Map<String, String> params) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
this.params = params;
}
// 設定逾時
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(timeOut,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
@Override
public String getBodyContentType() {
// TODO Auto-generated method stub
return PROTOCOL_CONTENT_TYPE;
}
// 添加header
private void setHeaders(String key, String value) {
headers.put(key, value);
}
// 設定逾時時間
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
@Override
public byte[] getBody() throws AuthFailureError {
try {
return mRequestBody == null ? null : mRequestBody
.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog
.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
// TODO Auto-generated method stub
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
@Override
protected void deliverResponse(T t) {
mListener.onResponse(t);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
// 得到伺服器傳回的資料
String strObject = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
// 轉化為泛型的對象
T parsedGSON = mGson.fromJson(strObject, mClass);
return Response.success(parsedGSON,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
Log.e("error", e.getMessage().toString());
return Response.error(new ParseError(e));
}
}
這個是我做項目的時候寫的 裡面的方法不一定都要實作 根據自己的實際情況去寫 接下來引用網上的一段代碼看一下簡單的寫法
- 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);
- }
- @Override
- protected 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));
- }
- }
- @Override
- protected void deliverResponse(T response) {
- mListener.onResponse(response);
- }
- }
這段代碼是比較簡單的 上一段代碼是根據我自己的需要編寫的 從這兩段代碼我們就可以看出來 下面兩個方法我們是必須要實作的 parseNetworkResponse這個方法就是用Gson對伺服器的響應就行解析 然後deliverResponse方法提供我們進行回調
有人會問那我們怎麼進行請求呢 好 我們直接上代碼
// 請求伺服器
public <T> void requestGet(int requestType, String urlStr, final int tag,
Map<String, Object> map, Class<T> cls) {
GsonRequest<T> mRequest = new GsonRequest<T>(requestType, returnGetUrl(
urlStr, map), cls, new Listener<T>() {
@Override
public void onResponse(T t) {
responseInterface.successResponse(t, tag);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
responseInterface.errorResonse(arg0.getMessage(), tag);
}
});
mRequest.setTag(tag);
BaseApplication.getRequestQueuemanager().add(mRequest);
}
我們看有五個參數第一個是請求方式是get還是post第二個是URL 第三個是tag 這個參數待會我們回調的時候會判斷是傳回的哪個實體類或者實體類的集合
第四個參數是我們傳入的參數 我當時用的Get 所有需要把參數拼接到URL後面 是以我們看到returnGetUrl這個方法就是我用來拼接參數的一個自定義方法
// 拼接請求
public String returnGetUrl(String url, Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
sb.append(url);
// 不同的背景 append後面的拼接不同
sb.append("&jsonstring=");
// sb.append(StringTools.correctEncode(returnGetPara(map)));
sb.append(returnGetPara(map));
return sb.toString();
}
BaseApplication.getRequestQueuemanager().add(mRequest);這句話大家應該能看明白吧 我當時說過 RequestQueue是在Application進行初始化。mRequest.setTag(tag);這句話就是設定Tag 好了 這就是一個請求。 responseInterface.successResponse(t, tag);這句話是我自定義一個接口 暴漏出請求到的資料(我們在外面Activity中隻需要實作這個ResponseInterface 接口 注冊一下就可以接收到我們傳回的資料了)
// 請求接口
public interface ResponseInterface {
// 請求成功以後的回調
public <T> void successResponse(T parsedGSON, int tag);
// 請求失敗的回調
public void errorResonse(String retmeg, int tag);
}
這時候你可能看的有點暈 這都哪跟哪啊 别急 我待會把我背景處理的三個類給大家貼出來 待會肯定明白
現在我們整個的自定義Request就講完了 現在我把我做項目寫的三個類給大家貼出來供大家參考 大家根據自己的需要去修改
package com.firstmortgage.net;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.util.Log;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyLog;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
public class GsonRequest<T> extends Request<T> {
private static final String PROTOCOL_CHARSET = "utf-8";
private static final String PROTOCOL_CONTENT_TYPE = String.format(
"application/json; charset=%s", PROTOCOL_CHARSET);
private Gson mGson;
// 上下文
private Context context;
// 監聽器
private Listener<T> mListener;
// 泛型類(解析的Bean類型)
private Class<T> mClass;
// 上傳的參數
private String mRequestBody;
private Map<String, String> params = new HashMap<String, String>();
private Map<String, String> headers = new HashMap<String, String>();
private int timeOut = 35000;
public GsonRequest(int method, String url, String mRequestBody,
Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mRequestBody = mRequestBody;
this.mListener = listener;
}
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
}
public GsonRequest(int method, String url, Class<T> clazz,
Listener<T> listener, ErrorListener errorListener,
Map<String, String> params) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.mListener = listener;
this.params = params;
}
// 設定逾時
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(timeOut,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
@Override
public String getBodyContentType() {
// TODO Auto-generated method stub
return PROTOCOL_CONTENT_TYPE;
}
// 添加header
private void setHeaders(String key, String value) {
headers.put(key, value);
}
// 設定逾時時間
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
@Override
public byte[] getBody() throws AuthFailureError {
try {
return mRequestBody == null ? null : mRequestBody
.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog
.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
// TODO Auto-generated method stub
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
@Override
protected void deliverResponse(T t) {
mListener.onResponse(t);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
// 得到伺服器傳回的資料
String strObject = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
// 轉化為泛型的對象
T parsedGSON = mGson.fromJson(strObject, mClass);
return Response.success(parsedGSON,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
Log.e("error", e.getMessage().toString());
return Response.error(new ParseError(e));
}
}
}
package com.firstmortgage.net;
import java.net.URLEncoder;
import java.util.Map;
import android.content.Context;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.Volley;
import com.firstmortgage.BaseApplication;
import com.firstmortgage.common.Constants;
import com.google.gson.Gson;
import com.squareup.okhttp.OkHttpClient;
//Request管類
public class RequestManager {
// 自定義接口
private ResponseInterface responseInterface;
// Gson解析
private Gson gson;
private OkHttpClient okHttpClient;
// 構造函數
private RequestManager(Context context) {
gson = new Gson();
okHttpClient = new OkHttpClient();
}
// 請求伺服器
public <T> void requestGet(int requestType, String urlStr, final int tag,
Map<String, Object> map, Class<T> cls) {
GsonRequest<T> mRequest = new GsonRequest<T>(requestType, returnGetUrl(
urlStr, map), cls, new Listener<T>() {
@Override
public void onResponse(T t) {
responseInterface.successResponse(t, tag);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
responseInterface.errorResonse(arg0.getMessage(), tag);
}
});
mRequest.setTag(tag);
BaseApplication.getRequestQueuemanager().add(mRequest);
}
// 拼接請求(.net做背景 不同的背景 不同的拼接請求)
public String returnGetUrl(String url, Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
sb.append(url);
// 不同的背景 append後面的拼接不同
sb.append("&jsonstring=");
// sb.append(StringTools.correctEncode(returnGetPara(map)));
sb.append(returnGetPara(map));
return sb.toString();
}
// 拼接請求參數
public String returnGetPara(Map<String, Object> params) {
String utfStr = "";
try {
utfStr = URLEncoder.encode(gson.toJson(params), Constants.CodeType);
} catch (Exception e) {
utfStr = "";
}
return utfStr;
}
public static RequestQueue newRequestQueue(Context context) {
RequestQueue requestQueue;
HurlStack stack = new OkHttpStack();
requestQueue = Volley.newRequestQueue(context);
requestQueue.start();
return requestQueue;
}
// 注冊
public void setResponseListener(ResponseInterface mResponseInterface) {
this.responseInterface = mResponseInterface;
}
// 請求接口
public interface ResponseInterface {
// 請求成功以後的回調
public <T> void successResponse(T parsedGSON, int tag);
// 請求失敗的回調
public void errorResonse(String retmeg, int tag);
}
}
package com.firstmortgage;
import java.io.File;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
import com.firstmortgage.net.OkHttpStack;
import com.firstmortgage.net.RequestManager;
import com.firstmortgage.util.ScreenManager;
import com.loopj.android.http.AsyncHttpClient;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.WeakMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.utils.StorageUtils;
import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap;
//程式入口
public class BaseApplication extends Application {
private static BaseApplication mBaseApplication;
private Context context;
public ScreenManager mScreenManager = null;
private static RequestQueue mRequestQueue;
// Vollery 管理器 單例
public static RequestQueue getRequestQueuemanager() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mBaseApplication);
}
return mRequestQueue;
}
// 單例的BaseApplication
public static BaseApplication getInstance() {
if (mBaseApplication == null) {
mBaseApplication = new BaseApplication();
}
return mBaseApplication;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
mBaseApplication = this;
context = this;
}
}
我們在Activity使用的時候隻需要讓Activity implements ResponseInterface 然後會回調接口裡面的兩個成功跟失敗的方法 還有重要的是 一定要注冊一下mRequestManager = new RequestManager(); mRequestManager.setResponseListener(this);寫在onCreat裡面就可以了 (這裡的注冊隻是針對我寫這個 我為了友善将資料暴漏出來了 記住隻是針對我寫的這個我需要注冊 大家根據自己的需要去寫)
總結;
到這裡我們這個完整的自定義Request就寫完了
1.自定義GsonRequest繼承Request實作裡面的方法 parseNetworkResponse deliverResponse和構造函數我們必須要實作的 其他的根據自己的需要去實作
2.建議程式設計習慣好的人 去寫一個RequestManager 專門管理咱們這個自定義的Request 然後定義一個接口把咱們請求的資料暴漏出去
好了 !!!明天咱們具體來看一下 Volley的整個架構 看一下内部是具體怎麼實作的