Android中volley封装实践记录(二)
前言
关于android的volley封装之前写过一篇文章,见链接(https://www.jb51.net/article/155875.htm)。这篇文章主要是换种方式进行封装,具体步骤如下所示。
步骤如下
1.创建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,比如超时时间,最大的重试次数。例外也会根据业务要求在请求的头部加入token等标识。
2.通过工厂模式创建请求队列,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(); }
最后放一张图:
图片发自简书App
分享结束,代码在[github] (https://github.com/daydaydate/sample (本地下载)) 。感谢您的阅读。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。
赞 (0)