Android中volley封裝實踐記錄(二)
前言
關于android的volley封裝之前寫過一篇文章,見鏈接(http://www.dbjr.com.cn/article/155875.htm)。這篇文章主要是換種方式進行封裝,具體步驟如下所示。
步驟如下
1.創(chuàng)建Request,并設置相應的參數:
public class CommonJsonObjectRequest extends JsonObjectRequest {
private String TAG = this.getClass().getSimpleName();
/*
* code=1:處理成功;
*/
public static final int CODE_SUCCESS = 100;
private Context mContext;
private JSONObject mJsonRequest;
public CommonJsonObjectRequest(Context context, int method, String url,
JSONObject jsonRequest, Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
super(method, url, jsonRequest, listener, errorListener);
init(context, jsonRequest);
}
/**
* @param context
* @param url
* @param jsonRequest
* @param listener
* @param errorListener
*/
public CommonJsonObjectRequest(Context context, String url, JSONObject jsonRequest,
Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
super(url, jsonRequest, listener, errorListener);
if (jsonRequest != null) {
Log.d(TAG, jsonRequest.toString());
}
init(context, jsonRequest);
}
/**
* @param context
* @param jsonRequest
*/
private void init(Context context, JSONObject jsonRequest) {
this.mContext = context.getApplicationContext();
this.mJsonRequest = jsonRequest;
setRetryPolicy(new DefaultRetryPolicy(10 * 1000, 0, 0));
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headersMap = new HashMap<>();
//do your business requirement
return headersMap;
}
}
所做的工作也很簡單,去配置網絡訪問RetryPolicy,比如超時時間,最大的重試次數。例外也會根據業(yè)務要求在請求的頭部加入token等標識。
2.通過工廠模式創(chuàng)建請求隊列,volley內部會有兩種構造方式,同步請求或者異步請求,通過設置ResponseDelivery 可以實現。
public interface ResponseDelivery {
/**
* Parses a response from the network or cache and delivers it.
*/
public void postResponse(Request<?> request, Response<?> response);
/**
* Parses a response from the network or cache and delivers it. The provided
* Runnable will be executed after delivery.
*/
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
/**
* Posts an error for the given request.
*/
public void postError(Request<?> request, VolleyError error);
}
這個工廠的代碼如下:
/**
* 網絡請求隊列工廠類
*/
public class RequestQueueFactory {
private static RequestQueue sRequestQueue;
private static RequestQueue sAsynRequestQueue;
private static int ASYN_QUEUE_THREAD_POOL_SIZE = 3;
private RequestQueueFactory() {
}
/**
* 獲取默認RequestQueue,回調是同步到主線程的
*
* @param context
* @return
*/
public synchronized static RequestQueue getRequestQueue(Context context) {
if (sRequestQueue == null) {
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
OkHttpStack stack = new OkHttpStack(okHttpClient);
sRequestQueue = Volley.newRequestQueue(context, stack);
}
return sRequestQueue;
}
/**
* 獲取異步RequestQueue,回調是在異步線程的
*
* @param context
* @return
*/
public synchronized static RequestQueue getAsynRequeQueueRespond(
final Context context) {
if (sAsynRequestQueue == null) {
sAsynRequestQueue = getAsynRequeQueueRespond(context,
ASYN_QUEUE_THREAD_POOL_SIZE);
}
return sAsynRequestQueue;
}
private static RequestQueue getAsynRequeQueueRespond(final Context context,
int threadPoolSize) {
File cacheDir = new File(context.getCacheDir(), "volley_asyn");
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
OkHttpStack stack = new OkHttpStack(okHttpClient);
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir),
network, threadPoolSize, new ExecutorDelivery(
AsyncTask.SERIAL_EXECUTOR));
queue.start();
return queue;
}
}
在代碼中有這樣兩行代碼:
if (sRequestQueue == null) {
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
OkHttpStack stack = new OkHttpStack(okHttpClient);
sRequestQueue = Volley.newRequestQueue(context, stack);
}
這里是使用了okhttpstack,如果不進行設置,內部默認的會設置一個stack;
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
okhttpstack類如下:
/**
* 使用OKHttp作為底層的HttpStack
*/
public class OkHttpStack implements HttpStack {
private final OkHttpClient client;
public OkHttpStack(OkHttpClient client) {
this.client = client;
}
private static HttpEntity entityFromOkHttpResponse(Response response) throws IOException {
BasicHttpEntity entity = new BasicHttpEntity();
ResponseBody body = response.body();
entity.setContent(body.byteStream());
entity.setContentLength(body.contentLength());
entity.setContentEncoding(response.header("Content-Encoding"));
if (body.contentType() != null) {
entity.setContentType(body.contentType().type());
}
return entity;
}
@SuppressWarnings("deprecation")
private static void setConnectionParametersForRequest
(okhttp3.Request.Builder builder, Request<?> request)
throws IOException, AuthFailureError {
switch (request.getMethod()) {
case Request.Method.DEPRECATED_GET_OR_POST:
byte[] postBody = request.getPostBody();
if (postBody != null) {
builder.post(RequestBody.create
(MediaType.parse(request.getPostBodyContentType()), postBody));
}
break;
case Request.Method.GET:
builder.get();
break;
case Request.Method.DELETE:
builder.delete();
break;
case Request.Method.POST:
builder.post(createRequestBody(request));
break;
case Request.Method.PUT:
builder.put(createRequestBody(request));
break;
case Request.Method.HEAD:
builder.head();
break;
case Request.Method.OPTIONS:
builder.method("OPTIONS", null);
break;
case Request.Method.TRACE:
builder.method("TRACE", null);
break;
case Request.Method.PATCH:
builder.patch(createRequestBody(request));
break;
default:
throw new IllegalStateException("Unknown method type.");
}
}
private static RequestBody createRequestBody(Request request) throws AuthFailureError {
final byte[] body = request.getBody();
if (body == null) return null;
return RequestBody.create(MediaType.parse(request.getBodyContentType()), body);
}
private static ProtocolVersion parseProtocol(final Protocol protocol) {
switch (protocol) {
case HTTP_1_0:
return new ProtocolVersion("HTTP", 1, 0);
case HTTP_1_1:
return new ProtocolVersion("HTTP", 1, 1);
case SPDY_3:
return new ProtocolVersion("SPDY", 3, 1);
case HTTP_2:
return new ProtocolVersion("HTTP", 2, 0);
}
throw new IllegalAccessError("Unkwown protocol");
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
int timeoutMs = request.getTimeoutMs();
OkHttpClient client = this.client.newBuilder()
.readTimeout(timeoutMs, TimeUnit.MILLISECONDS)
.connectTimeout(timeoutMs, TimeUnit.MILLISECONDS)
.writeTimeout(timeoutMs, TimeUnit.MILLISECONDS)
.build();
okhttp3.Request.Builder okHttpRequestBuilder = new okhttp3.Request.Builder();
Map<String, String> headers = request.getHeaders();
for (Map.Entry<String,String> entry : headers.entrySet()) {
okHttpRequestBuilder.addHeader(entry.getKey(), entry.getValue());
}
for (Map.Entry<String,String> entry : additionalHeaders.entrySet()) {
okHttpRequestBuilder.addHeader(entry.getKey(), entry.getValue());
}
// for (final String name : headers.keySet()) { //entrySet的遍歷效率比keySet高上一個遍歷元素的速度
// okHttpRequestBuilder.addHeader(name, headers.get(name));
// }
// for (final String name : additionalHeaders.keySet()) {
// okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name));
// }
setConnectionParametersForRequest(okHttpRequestBuilder, request);
okhttp3.Request okhttp3Request = okHttpRequestBuilder.url(request.getUrl()).build();
Response okHttpResponse = client.newCall(okhttp3Request).execute();
StatusLine responseStatus = new BasicStatusLine
(
parseProtocol(okHttpResponse.protocol()),
okHttpResponse.code(),
okHttpResponse.message()
);
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromOkHttpResponse(okHttpResponse));
Headers responseHeaders = okHttpResponse.headers();
for (int i = 0, len = responseHeaders.size(); i < len; i++) {
final String name = responseHeaders.name(i), value = responseHeaders.value(i);
if (name != null) {
response.addHeader(new BasicHeader(name, value));
}
}
return response;
}
}
其中核心代碼在performRequest方法中。
3.封裝基類。基類使用abstract會更靈活,子類可以選擇性的重寫方法。
/**
* 網絡處理基類
*/
public abstract class BaseNetModel {
protected RequestQueue requestQueue;
protected Context context;
protected Object mTag;
protected BaseNetModel(Context context) {
this.context = context.getApplicationContext();
requestQueue = RequestQueueFactory.getAsynRequeQueueRespond(this.context);
}
protected BaseNetModel(Context context, boolean isAsyn) {
this.context = context.getApplicationContext();
requestQueue = isAsyn ? RequestQueueFactory.getAsynRequeQueueRespond(this.context)
: RequestQueueFactory.getRequestQueue(context);
}
/**
* 推薦用頁面ClassName+時間戳
*
* @param tag
*/
public void setTag(Object tag) {
this.mTag = tag;
}
public void destroy() {
if (mTag != null) {
cancelTaskByTag(mTag);
}
requestQueue = null;
context = null;
}
public void cancelTaskByTag(Object tag) {
if (requestQueue != null) {
requestQueue.cancelAll(tag);
}
}
public void addRequest(String path, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
addRequest(path, true, jsonRequest, listener, errorListener);
}
/**
* @param path 不帶域名的接口路徑
* @param withTag 是否帶上頁面的tag
* @param jsonRequest
* @param listener
* @param errorListener
*/
public void addRequest(String path, boolean withTag, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
addRequestUrl(path, withTag, jsonRequest, listener, errorListener);
}
/**
* @param url 完整接口地址
* @param withTag
* @param jsonRequest
* @param listener
* @param errorListener
*/
public void addRequestUrl(String url, boolean withTag, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
if (jsonRequest == null) {
jsonRequest = new JSONObject();
}
CommonJsonObjectRequest request = new CommonJsonObjectRequest(context, url, jsonRequest, listener, errorListener);
if (withTag && mTag != null) {
request.setTag(mTag);
}
requestQueue.add(request);
}
}
4.邏輯封裝。
這里選用的是一個新聞的接口,這種接口可以在聚合數據上申請,有的收費,有的免費。
public class NewsModel extends BaseNetModel {
public NewsModel(Context context) {
super(context);
}
public NewsModel(Context context, boolean isAsyn) {
super(context, isAsyn);
}
public void getInfo(Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) throws Exception {
JSONObject jsonObject = new JSONObject();
addRequest(INetConstant.NEWS, jsonObject, listener, errorListener);
}
}
接口的地址為:(http://v.juhe.cn/toutiao/index?type=&key=b2f8e4aeacfa310cabfadd5189bbe4d5)
5.開始使用。
NewsModel newsModel = new NewsModel(getActivity());
try {
newsModel.getInfo(new Response.Listener<JSONObject>() {
@Override
public void onResponse(final JSONObject response) {
ThreadUtils.runInUIThread(new Runnable() {
@Override
public void run() {
News news = new Gson().fromJson(response.toString(), News.class);
mAdapter.setData(news.getResult().getData());
}
});
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
} catch (Exception e) {
e.printStackTrace();
}
最后放一張圖:

圖片發(fā)自簡書App
分享結束,代碼在[github] (https://github.com/daydaydate/sample (本地下載)) 。感謝您的閱讀。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Android 圖片保存到相冊不顯示的解決方案(兼容Android 10及更高版本)
這篇文章主要介紹了Android 圖片保存到系統(tǒng)相冊不顯示的解決方案,幫助大家更好的理解和學習使用Android開發(fā),感興趣的朋友可以了解下2021-04-04
android獲取圖片尺寸的兩種方式及bitmap的縮放操作
這篇文章主要介紹了android獲取圖片尺寸的兩種方式及bitmap的縮放操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Android?ViewPager你可能不知道的刷新操作分享
這篇文章主要為大家詳細介紹了Android中ViewPager你可能不知道的刷新操作,文中的示例代碼講解詳細,具有一定的學習價值,需要的可以參考一下2023-05-05

