服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android中volley封装实践记录(二)

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

2022-09-23 16:25一朵喇叭花呜拉呜拉 Android

这篇文章主要给大家介绍了关于Android中volley封装的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

关于android的volley封装之前写过一篇文章,见链接(http://www.tuohang.net/article/244650.html)。这篇文章主要是换种方式进行封装,具体步骤如下所示。

步骤如下

1.创建Request,并设置相应的参数:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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 可以实现。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

这个工厂的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
 * 网络请求队列工厂类
 */
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;
 }
 
}

在代码中有这样两行代码:

?
1
2
3
4
5
if (sRequestQueue == null) {
 OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
 OkHttpStack stack = new OkHttpStack(okHttpClient);
 sRequestQueue = Volley.newRequestQueue(context, stack);
}

这里是使用了okhttpstack,如果不进行设置,内部默认的会设置一个stack;

?
1
2
3
4
5
6
7
8
9
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类如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
 * 使用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会更灵活,子类可以选择性的重写方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
 * 网络处理基类
 */
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.逻辑封装。

这里选用的是一个新闻的接口,这种接口可以在聚合数据上申请,有的收费,有的免费。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.开始使用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

延伸 · 阅读

精彩推荐