使用OKHttp3替换Volley的底层网络请求
来源:互联网 发布:网络歌手灰色天空 编辑:程序博客网 时间:2024/05/17 07:26
一、自定义Volley框架中处理网络请求的HttpStatck,下面我们就使用OKHttp3实现HttpStack的网络请求。
1、在build.gradle文件中添加依赖:
compile 'com.mcxiaoke.volley:library:1.0.19' compile 'com.squareup.okio:okio:1.6.0' compile 'com.squareup.okhttp3:okhttp:3.0.0-RC1'
2、实现volley框架里的HttpStack接口,使用OKHttp3替换Volley的底层网络请求。
package com.bolome.network.request;import com.android.volley.AuthFailureError;import com.android.volley.Request;import com.android.volley.toolbox.HttpStack;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.ProtocolVersion;import org.apache.http.StatusLine;import org.apache.http.entity.BasicHttpEntity;import org.apache.http.message.BasicHeader;import org.apache.http.message.BasicHttpResponse;import org.apache.http.message.BasicStatusLine;import java.io.IOException;import java.util.Map;import java.util.concurrent.TimeUnit;import okhttp3.Headers;import okhttp3.MediaType;import okhttp3.OkHttpClient;import okhttp3.Protocol;import okhttp3.RequestBody;import okhttp3.Response;import okhttp3.ResponseBody;/** * Created by android_ls on 16/1/10. */public class OkHttpStack implements HttpStack { private final OkHttpClient mClient; public OkHttpStack(OkHttpClient client) { this.mClient = 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 = mClient.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 (final String name : headers.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; }}
3、创建Volley队列RequestQueue
RequestQueue requestQueue = Volley.newRequestQueue(this, new OkHttpStack(new OkHttpClient()));
二、Volley是Google官方发布的异步网络请求框架,试用场景数据量小,通信频繁的网络操作。Volley 异步网络请求分析:
上图是官方给出的Volley架构图,蓝色为主线程,绿色为缓存线程,橙色是网络线程。总的来说,就是一个请求队列和三种线程,UI线程(1个),Cache线程(1个)和Network线程(默认是4个)。
1、UI线程负责添加请求任务,执行任务结果;
2、Cache线程负责检查缓存,命中后直接将任务结果分发到主线程;
3、Network线程由多个任务线程(NetworkDispatcher)组成的,相当于一个大小为size的线程池,这些线程会同时启动,并持续的从任务队列中获取待执行的任务,任务执行完后会将结果分发到UI线程。
4、Request:请求的抽象类。StringRequest、JsonRequest、ImageRequest 都是它的子类,表示某种类型的请求。可扩展性强。
5、RequestQueue.java:请求队列,里面包含一个CacheDispatcher(用于处理走缓存请求的调度线程)、NetworkDispatcher数组(用于处理走网络请求的调度线程),一个ResponseDelivery(返回结果分发接口),通过 start() 方法启动时会启动CacheDispatcher和NetworkDispatchers。然后看创建请求队列方法内的代码:
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } 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)); } } Network network = new BasicNetwork(stack); RequestQueue queue; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start(); return queue; }
看到这里,需要了解三个类的作用:
HttpStack.java:处理HTTP请求,返回请求结果。目前Volley中有基于 HttpURLConnection 的 HurlStack 和 基于 Apache HttpClient 的HttpClientStack。
Network.java:调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
Cache.java:缓存请求结果,Volley默认使用的是基于sdcard缓存的DiskBasedCache。NetworkDispatcher得到请求结果后判断是否需要存储在 Cache,CacheDispatcher会从 Cache 中取缓存结果。
创建Network需要HttpStatck,如果newRequestQueue传入的stack为null,API Level >= 9,采用基于 HttpURLConnection 的 HurlStack;小于 9,采用基于 HttpClient 的 HttpClientStack。
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)); }}
接下来启动所需的所有线程:
public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); }}
CacheDispatcher.java:继承自Thread,用于调度处理「缓存请求」。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。
NetworkDispatcher.java:继承自Thread,用于调度处理「网络请求」。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。
ResponseDelivery.java:分发结果的interface,postResponse以及postError。
接下来再回头看一下Volley的架构图。
第一步:把请求加入缓存队列
第二步:「缓存调度线程」CacheDispatcher从缓存队列中取出一个请求,如果缓存命中,就读取缓存响应并解析,然后将结果返回到主线程
第三步:缓存未命中,请求被加入网络请求队列,「网络调度线程」NetworkDispatcher轮询取出请求,HTTP请求传输,解析响应,写入缓存,然后将结果返回到主线程
总结:
在主线程中调用RequestQueue的add()方法来添加一个网络请求任务。
1、以请求方法(GET、POST、PUT…) + URL作为缓存KEY,根据cacheKey从缓存队列里获取该网络请求任务。
a、如果为空的话则把这个任务加入到网络请求队列中;
b、如果不为空的话再判断该缓存是否已过期,如果已经过期了则同样把这个任务 加入到网络请求队列中;
c、否则就认为不需要重发网络请求,直接使用缓存中的数据即可。
2、加入到网络请求队列中的任务
a、发送HTTP请求
b、解析响应结果,写入缓存,并回调主线程。
- 使用OKHttp3替换Volley的底层网络请求
- 使用OkHttp3网络请求的错误解析
- 访问网络的框架(Volley和OkHttp3)使用
- okhttp3的网络请求框架
- android网络请求组件(一)OkHttp3的封装使用
- Android网络请求框架Volley的使用
- Volley网络请求的简单封装使用
- android网络请求Volley框架的使用
- Volley网络请求框架的使用
- Volley的简单使用--请求网络
- Android 网络请求Volley的使用
- 网络请求之Volley的使用
- Android网络请求 ------ Volley的使用
- Android OkHttp3网络请求框架使用入门
- 使用okhttp3简单执行网络请求
- Android使用Volley请求网络
- 使用volley进行网络请求
- Volley网络请求使用讲解
- Java疯狂讲义第五章笔记
- iphone 添加qq邮箱.
- zzulioj--1613--少活一年?(稍微有点坑,水!)
- java中insert函数
- SQL Server: 如何查看数据和日志文件占用情况
- 使用OKHttp3替换Volley的底层网络请求
- android studio 导入第三方库的记录
- HashMap源码解析(JAVA 1.6)
- 设计模式-单例模式
- 1015. 德才论 (25)
- ubuntu15.10下wine问题
- 谈一点我对hibernate关联关系映射的看法
- 一个字体的设计
- 1016. 部分A+B (15)