使用OKHttp3替换Volley的底层网络请求

        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 异步网络请求分析:



![这里写图片描述](https://img-blog.csdn.net/20160110195407702)



上图是官方给出的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、解析响应结果,写入缓存,并回调主线程。



 


**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/263321a4b97cfcc12e95a253b09deea3.png)
![img](https://img-blog.csdnimg.cn/img_convert/54078e6afc05ecb568e4e96ead28d2c8.png)
![img](https://img-blog.csdnimg.cn/img_convert/14d89a415858f9ae645c2c062e296994.png)
![img](https://img-blog.csdnimg.cn/img_convert/a790c1dc6534349d197336a6eb98a838.png)
![img](https://img-blog.csdnimg.cn/img_convert/bd044fd27aed057cc71f8e23a82869b5.png)
![img](https://img-blog.csdnimg.cn/img_convert/99d5abcc7c381d51c967a3dc7c7a3c52.png)
![img](https://img-blog.csdnimg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)**
![img](https://img-blog.csdnimg.cn/img_convert/e1554426c25981fc0e82f57bf42d46be.png)



最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。

**小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!**

> 不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。




**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
![img](https://img-blog.csdnimg.cn/img_convert/4a2473c384afb51d95ff3352c1749f08.png)
[外链图片转存中...(img-JvrxGh0D-1712892076889)]



最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。

**小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!**

> 不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。




**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
[外链图片转存中...(img-WT8olpTi-1712892076890)]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值