Android高级架构师
由于篇幅问题,我呢也将自己当前所在技术领域的各项知识点、工具、框架等汇总成一份技术路线图,还有一些架构进阶视频、全套学习PDF文件、面试文档、源码笔记。
- 330页PDF Android学习核心笔记(内含上面8大板块)
-
Android学习的系统对应视频
-
Android进阶的系统对应学习资料
- Android BAT部分大厂面试题(有解析)
好了,以上便是今天的分享,希望为各位朋友后续的学习提供方便。觉得内容不错,也欢迎多多分享给身边的朋友哈。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
emm没什么好讲的,入口就是 execute()
,但这是同步的,我们需要改成异步的,就是enqueue()
换成自己写的,不封装就是这样:
OkHttpClient client = new OkHttpClient();
client.newCall(new Request.Builder()
.url(url)
.build())
.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG,“onFailure”);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG,“onResponse”);
}
});
嗨呀,用法顶多就这样,一般情况下我们都不会直接使用OkHttp,更多是用Retrofit。(Retrofit的低层是Okhttp,所以Retrofit能做的,OkHttp都能做)
所以我们就来分析OkHttp的源码,来分析它其中的Http是怎么工作的。
==========================================================================
分析源码从执行入口看起,在这里就是enqueue()
,发现它是从newCall()
调用的。所以最开始,我们来分析newCall
的代码,
//OkHttp使用结构
client.newCall(new Request.Builder()…).enqueue(…);
我们发现newCall
传入的是一个Request
,没错,我们后面用Builder模式拼的这一串玩意,其实就是Http的Request。我们点进newCall的源码:
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
↑括号中的参数就是一个正经的Requeset
对象。
再来看返回,函数的返回是 Call
类型,而下面实际return的是一个 new RealCall(.. request ..)
对象
也就是说,RealCall
是Call
的一个实现
我们点进RealCall:
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket){
…
this.eventListener = eventListenerFactory.create(this);
}
分析下构造参数
- OkHttpClient client
大总管,先不管
- Request originalRequest
这里的Request是我们通过Build()创建出来的,这里为什么叫originalRequest呢?
是因为后面我们会不断的对Request做操作(就是用拦截器啊!)把它这改一下那里改一下
- boolean forWebSocket
来判断是不是WebSocket,WebSocket就是Http的一种扩展(可以做到服务器对客户端做推送),一般都不是WebSocket
然后我们来看下下面的eventListener
,在http的一个完整的过程中,会有一些关键的时间点,比如 Http的响应,tcp层的建立等等,而在这些时间点产生的事件,则会通过 eventListener
去响应。
到这里,newCall就看完了,它就是产生一个 RealCall的对象。
接下来我们来看okhttp的入口 enqueue(Callback)
,因为它实际是由RealCall执行的,所以我们要去RealCall类中找enqueue()
方法:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
//并列执行
if (executed) throw new IllegalStateException(“Already Executed”);
executed = true;
}
captureCallStackTrace();
//这行信息量很大,也很重要
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
我们来看最后一行,看到dispatcher
就知道是分发器,它拿去分发Callback
了,并且分发之前,将它包装成一个 AsyncCall
对象。
我们先来啃Dispatcher
Dispather
它是一个线程管理工具。
因为Http的Request和Response要使用单独的线程,如果你有多个请求和返回,如果都放在同一个线程的话会被挡到,所以Dispatch来做到线程控制
看到Executor懂得人都懂了,它是专门处理线程的类。但这里不讲解了,它就是用来处理线程的。
还看到有 maxRequests和maxRequestsPerHost
- maxRequests
最多并列执行又这么多(64)的请求,后面多出来的请求就放在后面的队列等。
- maxRequestsPerHost
每个主机最多并列执行又这么多(5)的请求。多出来的往后稍稍。
Dispatcer的enqueue()方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
//如果当前并发执行的网络请求少于上限,则将该网络请求放到后台中执行
executorService().execute(call);
} else {
//否则放到ready队列等待
readyAsyncCalls.add(call);
}
}
这个方法比较简单,就是判断当前并行的网络请求有没有达到上限,有就等,没有就放到后台执行。
然后我们来看它具体执行的AsyncCall
对象。
AsyncCall
发现作为一个Call对象它是没有run方法的,所以我们要去它的父类 NamedRunnable
对象里面看。
发现NamedRunnable
实现了Runnable
方法并重写了run()方法,run方法里就是跑了 execute()
方法。
此execute()非彼execute(),点进它,它是 AsyncCall
继承该类重写的execute()方法。
这个execute()方法在 AsyncCall下,
想必最重要的是哪几行,大家都知道了。
Response response = getResponseWithInterceptorChain()
这行代码就突然Response了,这说明getResponseWithInterceptorChain()
把Http的请求响应给走完了。也就是说它是最最最最关键的方法了。
学到这里我们看了好几个类,它们大概做的就是为Http铺好一条路,让http请求更好走,比如给它安排了线程,给Request包装等等,我们看一下关键的步骤:
-
将请求
Requeset
通过newCall
方法包装成一个RealCall
-
执行
RealCall()
的enqueue()
方法,并且将Callback
回调作为参数代入 -
Dispatcher
给该Request分配线程,放在后台,执行Dispatch自己的execute()
方法 -
这个execute()方法内部执行了
getResponseWithInterceptorChain()
,该方法内部走完了http的传输细节,返回Response
。 -
Response
响应外面CallBack的onResponse()
和onFailure()
注:其实这里就可以看出OkHttp无论是enqueue()
还是execute()
,都会走getResponseWithInterceptorChain()
,因为execute()它不用切线程,所以它是直接执行该方法,而enqueue还要考虑当前请求是否太多,否则会造成阻塞,所以要用Dispatch来管理一下,再使用这个方法。
然后走完这个方法,就会去回调之前Callback的onResponse和onFailure方法了。
上面就是OkHttp的大框架了,其实很简单,所以外面用起来也很简单,好懂。
为了更深入的了解OkHttp,我们除了了解这些,还要去了解它里面的一些配置,和网络实现的细节。
也就是OkHttpClient
它是做什么的,和 getResponseWithInterceptorChain()
这个方法
我们先来看看OkHttpClient里面的全部配置。每个都注释一下,并讲述比较重要的对象:
//线程管理器,这个之前已经了解了
final Dispatcher dispatcher;
//代理类,帮我们配置网络信息
final @Nullable Proxy proxy;
//Protocol类里面列出了支持的Http版本,http1.0、1.1、2.0 SPDY3.1(http2的前身)
final List protocols;
//里面是Cipher Suite(如果是Https,那么这个Cipher suite就是TLS版本、对称加密、非对称加密、Hash算法…,让对方选,所以这里是一个列表)
//它有好几套Cipher Suite方案任君选择
final List connectionSpecs;
//这两个比较重要,等下会具体研究,它们大概就是对连接过程中的每一个阶段做处理
final List interceptors;
final List networkInterceptors;
//就是监听整个网络请求+返回过程
final EventListener.Factory eventListenerFactory;
//用处不大,不用了解了
final ProxySelector proxySelector;
//Jar是罐子的意思,CookieJar是存放Cookie的容器
final CookieJar cookieJar;
//Http的Cache
final @Nullable Cache cache;
final @Nullable InternalCache internalCache;
//Socket是Tcp的端口,这个就是Tcp端口的工厂
final SocketFactory socketFactory;
//Https下Tcp的端口
final @Nullable SSLSocketFactory sslSocketFactory;
//证书链,方便验证(https讲过)
final @Nullable CertificateChainCleaner certificateChainCleaner;
//Https验证的 主机名验证器, 验证对方的Host是不是想要访问的Host
final HostnameVerifier hostnameVerifier;
//直译叫证书固定器,用来做自签名,用来验证证书公钥,如果host的证书和这个对象传入(本地存的)的公钥一致,则证明对方是自己想要访问的一方。
final CertificatePinner certificatePinner;
//用来写 Authorization Bearer<…> 当权限不足的时候会报错 401
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
//线程连接池,可以有那么多的线程可以用来进行网络请求
final ConnectionPool connectionPool;
//DNS实现类
final Dns dns;
//重定向跳转, 默认为true,即跳转
final boolean followRedirects;
//https跳到http重定向,默认为true
final boolean followSslRedirects;
//当连接建立失败后,是否重试,默认为true
final boolean retryOnConnectionFailure;
//Tcp连接、读、写 超过该时间就跑错
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
//长连接,发送ping(相当于一个心跳)的时间间隔
final int pingInterval;
看完上面的配置还有一些注释,会很明白HTTP在OkHttp里面的配置,比较全而且清晰。
OkHttpClient
这个大总管它有关于Http、Https基本都有的配置信息,基本都是Header和Header有关的一些东西。
getResponseWithInterceptorChain()
OkHttp最核心的方法,相当于内部的入口。所以很有必要去了解。
我们先点进这个方法:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//第一部分
List interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
//第二部分
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//第三部分
return chain.proceed(originalRequest);
}
上面比较“麻雀虽小五脏俱全”的感觉,代码没那么多,但每一行都是核心。
它大概有三个部分:
-
装一些
Interceptor
到List中 -
构建一个
Interceptor Chain
-
使用chain的
proceed(originalRequest)
得到了网络响应的Response
我们用图分别来说下他们的概念:
首先这个方法会创建一个含有泛型为Interceptor
的List,并往这个List里面add几个系统自带的Interceptor。如上图所示。
而chain
的构造方法中带了这个List,也就是说,这个chain它其实是给这个List里的所有interceptor用一条链,按顺序给链了起来,如下图:
↑而且实际上,这条链并不是单向的,它走到走后的Interceptor后,会往回走。
原因很简单,chain的方向就是我们Request走的方向,我们把Request带过去(发送请求),最后会把Respnse带回来,回来的时候,也要这些Interceptor来处理结果。这就是chain。
为什么要用Chain和Interceptor,为什么不直接发到另一端去
那肯定是细节化啊。
万一你突然Request少了一个重要东西,我有必要在检查少了东西的这个环节进行上报,如果直接传过去,可能会产生不必要的开销。
chain的目的在于每个Interceptor都能够自定义的去处理这些事情,所以chain和Interceptor是多么滴重要。
process(request)
是做什么的呢?process是前进的意思。
概述:将Request
交个下一个Interceptor处理
将代码和图来讲一下:
它有三个情况,一个是将requeset,传过去,一个是等,一个是request/response回来:
尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
展示学习笔记
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
process(request)
是做什么的呢?process是前进的意思。
概述:将Request
交个下一个Interceptor处理
将代码和图来讲一下:
它有三个情况,一个是将requeset,传过去,一个是等,一个是request/response回来:
尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
[外链图片转存中…(img-XyjxemRN-1715115518537)]
展示学习笔记
[外链图片转存中…(img-xmKCRuF0-1715115518537)]
[外链图片转存中…(img-qi1z9CEX-1715115518537)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!