OKHttp 解析

Posted

tags:

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

参考技术A 分析网络访问框架的三个步骤,三个主线:

1、请求发送到哪去了?

call.enqueue()------equeue()

访问统一目标机器请求个数值,默认为5

<  5 时 加入运行状态队列 ,否则加入等待状态队列

2、请求是被谁处理了?

executorService 线程池,核心线程是0,最大数是maxValue,线程池内部维护等待队列,OKHTTP中是一个无容量队列,相当于来到请求就必须处理,没有线程时就会创建,所以就会是maxValue。

然后就到AsyncCall类,调用里边的execute()方法,这是真正处理请求的地方,然后走到getResponsewithInterceptorChain()方法,里边是一个责任链模式,
责任链模式:有一条链子,链子上有多个节点,每个节点都有成功或失败两个结果,这样做的好处是,我们在访问服务器的时候,可以在里边进行过滤,拦截无效请求。

重试拦截器、桥拦截器、缓存拦截器、连接拦截器、网络拦截器、。。。

经过拦截过滤后,才会发送到服务器的请求。

3、请求是怎么被维护的?

client.dispatch

HTTP请求开始:

client=new   OkHttpClient();
Request   request=new   Request.Builder().url("your url").build();
//同步发起请求
Response    syncResponse=client.newCall(request).execute();
//异步发起请求
client.newCall(request).enqueue(newCallback()

@Override

public   void   onFailure(@NotNullCallcall,@NotNullIOExceptione)


@Override
public   void   onResponse(@NotNullCallcall,@NotNullResponseresponse)throwsIOException


);

调用过程:

new OKHTTPClient()-----》client.newCall(request)----->execute()同步请求------->RealCall#getResponseWithInterceptorChain( )--------->RealInterceptorChain#proceed(request)

new OKHTTPClient()-----》client.newCall(request)----->enqueue()异步请求-----》Dispatcher.equeue( )---
---->Dispatcher#promoteAndExecute( )------>executeOn( )----->run( )----------------------------------------------------------------->RealCall#getResponseWithInterceptorChain( )--------->RealInterceptorChain#proceed(request)

OKHTTP中有五种拦截器   :缓存拦截、网络连接拦截、

自定义拦截器的三个步骤:

chain.request()

chain.proceed()

return response;

OKHTTP可以配置x509trustManager,设置TLS信任证书:

这块有一个坑,就是必须先要接受系统的证书,然后接受本地证书。否则访问一些链接会出现异常。

OKHTTP的请求队列使用的是SynchronousQueue,这个队列的特点是容量为0,来到请求就马上处理

面试题1:OKHTTP中的责任链是怎样串联起来的?请求回来的数据进行怎样线程切换?

答:串联方式,通过将各种拦截器加入一个集合中,创建一个RealInterceptorChain对象,传入这个拦截器集合,传入一个index为0,他本质上是一个Chain子类,会内部回调proceed()回调方法,在proceed()方法中,循环创建RealInterceptorChain对象,index每次加1,每次取出一个拦截器,拦截器调用回调方法intercept(),内部进行拦截执行,完成自己能干的事,然后返回一个response,经过这种方式将各个拦截器的执行串联起来。

异步方式会调用enqueue()方法,里边client.dispatcher().enqueue(new AsyncCall(responseCallback));这个AsyncCall实质上是一个Runable,在Runable的run方法中,调用execute(),他是一个待实现的方法,在execute()的实现方法中,调用getResponseWithInterceptorChain(),里边就是对于请求的拦截,通过回调将结果返回给onResponse(),注意,这里的返回结果,OKHTTP并没有给我们切回主线程。接下来的操作就是由我们自己完成了,可以使用handler完成接下来的操作、或者runOnUIThread()切回主线程。

由子线程得到结果后,想要在主线程更新UI,可以使用三种方式:

(1)runOnUiThread():内部实际上是做了线程判断,如果是主线程,那么直接执行,否则的话,会利用Activity中的默认创建的handler来执行,会调用handler.post(),而这个post方法也会调用sendMessage()

(2)handler.post(new Runnable),使用handler方法切回主线程时,注意handler的实例化要放在主线程中,而不能在新开的子线程中,否则报错,这是因为,Handler在哪里创建,就获得哪里的Looper。主线程创建的Handler,即默认使用主线程的Looper。即能否更新UI主要是看Looper是否在主线程。因为Looper是在创建它的线程执行的。

handler.post()----->sendMessageDelayed(getPostMessage(r), 0);本质上和sendMessage()一样,都是发送一条消息。

(3)view.post(new Runnable),回判断view的attachInfo字段是否为空,如果不为空,则获取attachInfo中的Handler对象,然后调用handler的post方法来进行线程切换。

面试题2:Handler sendMessageDelay()  是怎样执行的?

sendMessageDelay()方法,会在当前时间加上延时时间,然后在MessageQueue类的enqueueMessage()方法中,将这个时间赋值给msg.when ,代表消息执行时间,然后轮询器Looper调用loop循环的时候,循环取出消息队列中的msg,然后调用messageQueue的next()方法取下一条消息。方法内部会用当前时间与msg.when对比,如果小于,说明未到执行时间,则拿到两者的差值,下一次循环的时候调用nativePollOnce()方法,Linux内部会对各个消息重排序。等到执行时间到了之后,将消息返回给Looper。

面试题3:Glide缓存,该怎样存?

面试题4:Retrofit实现机制,数据回来之后的线程切换?

Retrofit内部使用动态代理、注解、反射来实现接口的封装,使用okhttp实现实现请求操作,实际上,在Retrofit创建过程中,在build方法里,

if (callbackExecutor ==null)

callbackExecutor =platform.defaultCallbackExecutor();



而这个platform.defaultCallbackExecutor();调用了,

static final class androidextends Platform

Android()

super(Build.VERSION.SDK_INT >=24);

 

@Override

  public ExecutordefaultCallbackExecutor()

return new MainThreadExecutor();

 

也就是创建了MainThreadExecutor()对象,

static final class MainThreadExecutor   implements Executor

private final Handlerhandler =new Handler(Looper.getMainLooper());

  @Override

  public void execute(Runnable r)

handler.post(r);

 



MainThreadExecutor   是一个静态内部终类,实际上创建了一个Handler,,里边传入的是主线程的Looper,前面创建的callbackExecutor,就是实现请求数据返回的接口类,从而就可以实现将请求数据通过handler传回主线程。

面试题5:HTTPS   中的TLS属于哪层协议?

答:属于应用层与传输层之间的协议,

Okhttp底层是通过java的socket请求与接受响应,(因为HTTP就是基于TCP的),但是okhttp实现了连接池的概念,即对于同一主机的多个请求,其实可以共用一个socket连接,而不是每次发送完HTTP请求就关闭底层socket,这样就实现了连接池的概念,而okhttp对于socket的读写操作使用的OKIO库进行的一层封装。

以上是关于OKHttp 解析的主要内容,如果未能解决你的问题,请参考以下文章

Android OkHttp完全解析 是时候来了解OkHttp了

OKHttp 解析

OkHttp源码解析笔记

OKHttp源码解析

Andriod OKHttp源码解析

OKHttp源码解析之网络请求