OKHttp分发器源码分析(两个版本)

Posted 高、远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OKHttp分发器源码分析(两个版本)相关的知识,希望对你有一定的参考价值。

文章目录

【1】简介

OkHttp是当下android使用最频繁的网络请求框架,由Square公司开源。 Google在Android4.4以后开始将源码中的HttpURLConnection底层实现替换为0KHttp,同时现在流行的Retrofit框架底层同样是使用OKHttp的。

我们将了解下OKHttp的源码,但是不同的版本源码会有一些差异,等下我会大概说一下3.10.04.9.3版本的不同之处


【2】简单使用(略谈)

大家应该都用过OKHttp,只是你们自己可能都不知道,因为我们项目中经常使用的是像Retrofit这样的网络框架,但其实Retrofit是基于OKHttp进行的再次封装,将返回的结果等进行了一些更加人性化的封装,更便于我们开发使用。

①使用流程图如下:

②使用代码如下:

//1
        OkHttpClient okHttpClient = new OkHttpClient();
        
        //2
        Request request = new Request.Builder()
                .url("www.baidu.com")
                .build();
        //3
        Call call = okHttpClient.newCall(request);
        
        //4异步请求
        call.enqueue(new Callback() 
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) 

            

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException 

            
        );
        
        //或者同步请求
        try 
            Response response = call.execute();
         catch (IOException e) 
            e.printStackTrace();
        

其实看了这个发现OKHttp重要的还是分发器和拦截器,那么下面我们就来讲一下什么是分发器、拦截器,他们有什么用,是怎么工作的。


【3】分发器(两个版本)

Dispatcher 分发器就是来调配请求任务的,内部会包含一个线程池(异步任务才会用到)。可以在创建 OkHttpClient 时,传递我们 自己定义的线程池来创建分发器。下面我们跟着源码追一下吧,我们看异步的,同步的可以自行查看比较简单。

一、OKHttp 3.10.0版本的分发器源码追溯

①从这里进去

②Call只有一个默认实现类RealCall

③进到RealCallenqueue中,发现要去到dispatcherenqueue

④分发器中的enqueue

分发器异步任务的时候有两个队列

  • runningAsyncCalls
  • readyAsyncCalls

running当前任务数小于规定的max值(默认64)(考虑到手机压力)
running队列里面正在访问的host和当前host相同的任务不能超过5个(减少服务器压力)

当正在执行的任务未超过最大限制64,同时 runningCallsForHost(call) < maxRequestsPerHost 同一Host的请求 不超过5个,则会添加到正在执行队列,同时提交给线程池直接执行。否则先加入等待队列。

⑤线程池执行应该是找到AsyncCall的run方法

但他没有run方法,而且继承的也不是Runable对象,我们看下NamedRunnable到底是个什么东西



原来如此,有个抽象的execute方法在run里面执行,所以线程池就会执行AsyncCallexecute方法了



try和catch先不管看到finally,会执行finished方法



将这个任务从runningAsyncCalls中移除,然后命中if语句,进入promoteCalls



遍历readyAsyncCalls中的任务,根据判断的规则将任务加入到runningAsyncCalls中然后调用线程池进行执行。

现在我们想想是不是分发器我们已经走完一遍了?不是要从分发器到拦截器吗?根据我们上面的整体流程图应该是这样的,那我们什么时候进入到拦截器的呢?其实是在execute方法的时候:

二、OKHttp4.9.3版本的源码分析


②又是这个接口还是只有RealCall这个默认实现类

③进入到RealCallenqueue

④来到dispatcherenqueue方法中

这里已经是不一样的了,这里不再判断,而是直接将任务加入到readyAsyncCalls中,然后调用promoteAndExecute


遍历,然后根据上面相同的条件,是否将任务加入到runningAsyncCalls中,另外多了一个队列executableCalls


然后遍历执行executableCalls队列中的任务


⑨还是要来到dispatcherfinished方法

这个版本的源码我没有详细讲解,但是你们应该都看得懂。跟3.10.0版本的有一些区别,但是也有很多相似的地方

三、两个不同版本的执行流程比较:

①3.10.0版本的流程

②4.9.3版本的流程

四、分发器中的线程池

这里由于篇幅,不再详细说明,这里线程池的队列用的无界队列SynchronousQueue

核心线程数为0,最大线程数为Integer.MAX_VALUE
实现了一个最大并发量的线程池

以上是关于OKHttp分发器源码分析(两个版本)的主要内容,如果未能解决你的问题,请参考以下文章

OKHttp分发器源码分析(两个版本)

OkHttp3 源码分析

OkHttp3 源码分析

OkHttp3 源码分析

OkHttp源码中Dispatcher和connectionPool线程池分析

OkHttp源码中Dispatcher和connectionPool线程池分析