软件编程
位置:首页>> 软件编程>> Android编程>> Android中volley封装实践记录(二)

Android中volley封装实践记录(二)

作者:一朵喇叭花呜拉呜拉  发布时间:2023-05-17 02:37:13 

标签: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();
}

最后放一张图:

Android中volley封装实践记录(二)

图片发自简书App

分享结束,代码在[github] (https://github.com/daydaydate/sample (本地下载))  。感谢您的阅读。

来源:https://www.jianshu.com/p/d110d047fde0

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com