by hzwusibo? 20190504
常見問題一:簡述一下OkHttp
OkHttp已被谷歌加入到Android的源碼中。目前比較流行的Retrofit也是默認(rèn)使用OkHttp的。
支持http2,對一臺機(jī)器的所有請求共享同一個(gè)socket
內(nèi)置連接池,支持連接復(fù)用,減少延遲
支持透明的gzip壓縮響應(yīng)體
通過緩存避免重復(fù)的請求
請求失敗時(shí)自動重試主機(jī)的其他ip,自動重定向
好用的API
關(guān)于 HTTP2 和 HTTPS,這些你必須要知道
http://www.itdecent.cn/p/bf1db5c4d2d2
常見問題二:看過OkHttp的源碼嗎,簡單說一下

(一)、總體設(shè)計(jì)
第一,通過一個(gè)構(gòu)建者模式(Request.Builder)構(gòu)建所有的request;然后分發(fā)到Dispatcher(分發(fā)器);
第二,Dispatcher再把request分發(fā)到HttpEngine(真正干活的類)中,HttpEngine首先要看一下本次請求有沒有cache(緩存),如果有緩存,就從緩存中拿到信息,然后返回給response;如果沒有緩存,HttpEngine就把request分發(fā)到ConnectionPool(連接池)中;
第三,在ConnectionPool(連接池)中,通過Connection發(fā)送請求,通過Route(路由)和Platfrom(平臺),到達(dá)Server(Socket),獲取到Data,然后返回response。
(二)、流程圖

上面是OKHttp總體設(shè)計(jì)圖,主要是通過Diapatcher不斷從RequestQueue中取出請求(Call),根據(jù)是否已緩存調(diào)用Cache或Network這兩類數(shù)據(jù)獲取接口之一,從內(nèi)存緩存或是服務(wù)器取得請求的數(shù)據(jù)。該引擎有同步和異步請求,同步請求通過Call.execute()直接返回當(dāng)前的Response,而異步請求會把當(dāng)前的請求Call.enqueue添加(AsyncCall)到請求隊(duì)列中,并通過回調(diào)(Callback)的方式來獲取最后結(jié)果。
OkHttp使用教程
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
Dispatcher線程池總結(jié)
1)調(diào)度線程池Disptcher實(shí)現(xiàn)了高并發(fā),低阻塞的實(shí)現(xiàn)?
2)采用Deque作為緩存,先進(jìn)先出的順序執(zhí)行?
3)任務(wù)在try/finally中調(diào)用了finished函數(shù),控制任務(wù)隊(duì)列的執(zhí)行順序,而不是采用鎖,減少了編碼復(fù)雜性提高性能。
Android面試題-OkHttp3源碼分析
https://blog.csdn.net/mwq384807683/article/details/71173442?locationNum=8&fps=1
OkHttp通過定義許多攔截器一步一步地對Request進(jìn)行攔截處理,直到請求返回網(wǎng)絡(luò)數(shù)據(jù),后面又倒過來,一步一步地對Response進(jìn)行攔截處理,最后攔截的結(jié)果就是回調(diào)的最終Response。
RealInterceptorChain的proceed方法,通過順序地傳入一個(gè)攔截器的集合,創(chuàng)建一個(gè)RealInterceptorChain,然后拿到之前OkHttp創(chuàng)建的各種攔截器,并調(diào)用其interrupt方法,并返回Response對象。其調(diào)用順序如下:

1)在配置 OkHttpClient 時(shí)設(shè)置的 interceptors;
2)負(fù)責(zé)失敗重試以及重定向的 RetryAndFollowUpInterceptor;
3)負(fù)責(zé)把用戶構(gòu)造的請求轉(zhuǎn)換為發(fā)送到服務(wù)器的請求、把服務(wù)器返回的響應(yīng)轉(zhuǎn)換為用戶友好的響應(yīng)的 BridgeInterceptor;
4)負(fù)責(zé)讀取緩存直接返回、更新緩存的 CacheInterceptor;
5)負(fù)責(zé)和服務(wù)器建立連接的 ConnectInterceptor;
6)配置 OkHttpClient 時(shí)設(shè)置的 networkInterceptors;
7)負(fù)責(zé)向服務(wù)器發(fā)送請求數(shù)據(jù)、從服務(wù)器讀取響應(yīng)數(shù)據(jù)的 CallServerInterceptor。
OkHttp的這種攔截器鏈采用的是責(zé)任鏈模式,這樣的好處是將請求的發(fā)送和處理分開,并且可以動態(tài)添加中間的處理方實(shí)現(xiàn)對請求的處理、短路等操作
責(zé)任鏈模式是一種對象的行為模式。在責(zé)任鏈模式里,很多對象由每一個(gè)對象對其下家的引用而連接起來形成一條鏈。請求在這個(gè)鏈上傳遞,直到鏈上的某一個(gè)對象決定處理此請求。發(fā)出這個(gè)請求的客戶端并不知道鏈上的哪一個(gè)對象最終處理這個(gè)請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織和分配責(zé)任。
可以看到 OkHttp 的線程池配置如下:
核心線程數(shù):0
最大線程數(shù):Iteger.MAX_VALUE,其實(shí)就是不限制
空閑線程?;顣r(shí)間:60s
任務(wù)隊(duì)列:SynchronousQueue,為有界隊(duì)列,且隊(duì)列大小為 0,不存 Runnable,只是用來進(jìn)行生產(chǎn)者和消費(fèi)者之間的傳遞任務(wù)。
是不是很眼熟?和我們在 Executors 使用的 緩存線程池的配置完全一樣,緩存線程池的代碼如下:
? ? public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
? ? ? ? return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 60L, TimeUnit.SECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new SynchronousQueue<Runnable>(),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? threadFactory);
? ? }
所以 OkHttp 自己創(chuàng)建的這個(gè)線程池,和緩存線程池的區(qū)別,僅僅是修改了線程名。
我們簡要分析一下緩存線程池的運(yùn)行機(jī)制,進(jìn)入到 ThreadPoolExecutor 中的execute方法的源碼中,假設(shè)線程池處于運(yùn)行狀態(tài),會有這樣的流程:
新過來一個(gè)任務(wù),由于核心線程數(shù)為 0,不需要創(chuàng)建核心線程,所以嘗試加入任務(wù)隊(duì)列
如果線程池中有線程剛好空閑可以接收任務(wù),因?yàn)槿蝿?wù)隊(duì)列的類型是 SynchronousQueue,實(shí)際大小為 0,只做消費(fèi)者和生產(chǎn)者的中轉(zhuǎn)站,所以這時(shí)候,就可以入列成功,通過 SynchronousQueue 中轉(zhuǎn)任務(wù)給空閑的線程執(zhí)行。
如果當(dāng)前線程池所有線程工作飽和,會入列失敗。這時(shí)候 ThreadPoolExecutor 會調(diào)用addWorker(command, false)來創(chuàng)建并且啟動新線程。
這樣子,就會產(chǎn)生疑問,那么如果一次性同時(shí)發(fā)起大量的請求,不就會產(chǎn)生大量線程了?比如我一次性發(fā)起 100 個(gè)請求,那么是不是會發(fā)出 100 個(gè)線程?
是的,如果直接使用該線程池而沒有其他的策略的話,是有這樣的問題。
所以在 OkHttp 中線程池只是一個(gè)輔助作用,僅僅是用來做線程緩存,便于復(fù)用的。真正對這些請求的并發(fā)數(shù)量限制,執(zhí)行時(shí)機(jī)等等都是調(diào)度器 Dispatcher 承擔(dān)的。在 OkHttp 這里,線程池只是個(gè)帶緩存功能的執(zhí)行器,而真正的調(diào)度是外部包了一個(gè)調(diào)度策略的。

https://www.cnblogs.com/hankzhouAndroid/p/8710284.html
Retrofit

OkHttp和Retrofit的聯(lián)系
http://www.itdecent.cn/p/4d67fe493ebf
Retrofit負(fù)責(zé)請求的數(shù)據(jù)和請求的結(jié)果,使用接口的方式呈現(xiàn)(注解)。
OkHttp負(fù)責(zé)請求的過程。
RxJava負(fù)責(zé)異步,各種線程之間的切換。
Retrofit是Square開源的一款適用于Android網(wǎng)絡(luò)請求的框架。Retrofit底層是基于OkHttp實(shí)現(xiàn)的,與其他網(wǎng)絡(luò)框架不同的是,它更多使用運(yùn)行時(shí)注解的方式提供功能。
1.Retrofit優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
?? 可以配置不同HTTP client來實(shí)現(xiàn)網(wǎng)絡(luò)請求,如okhttp、httpclient等;
?? 請求的方法參數(shù)注解都可以定制;
?? 支持同步、異步和RxJava;
?? 解耦;
?? 可以配置不同的反序列化工具來解析數(shù)據(jù),如json、xml等;
?? 使用非常方便靈活;
2.Retrofit注解

Retrofit注解分為三大類,分別是HTTP請求方法注解(8種)、標(biāo)記類注解(3種)和參數(shù)類注解(11種)。
??HTTP請求方法注解:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、HTTP
??標(biāo)記類注解:FormUrlEncoded、Multipart、Streaming
??參數(shù)類注解:Headers、Header、Body、Field、FieldMap、Part、PartMap、Path、Query、QueryMap、Url
Retrofit底層對網(wǎng)絡(luò)的訪問默認(rèn)是基于okhttp,不過Retrofit非常適合于restful url格式的請求,更多使用注解的方式提供功能。
Retrofit框架網(wǎng)絡(luò)請求流程圖
網(wǎng)絡(luò)請求:APP發(fā)起網(wǎng)絡(luò)請求,Retrofit通過注解配置請求參數(shù)、Header、Url之后,通過OkHttp發(fā)生網(wǎng)絡(luò)請求給服務(wù)器。
服務(wù)器響應(yīng):服務(wù)器返回響應(yīng)數(shù)據(jù),OkHttp將數(shù)據(jù)傳遞給Retrofit,再把數(shù)據(jù)直接傳遞給APP,界面刷新反饋結(jié)果給用戶。
OkHttp和Retrofit都是網(wǎng)絡(luò)開源框架,但是他們之間的區(qū)別請不要混淆:
職責(zé)不同:
??Retrofit主要負(fù)責(zé)應(yīng)用層面的封裝,就是說主要面向開發(fā)者,方便使用,比如請求參數(shù),響應(yīng)數(shù)據(jù)的處理,錯誤處理等等。
??OkHttp主要負(fù)責(zé)socket部分的優(yōu)化,比如多路復(fù)用,buffer緩存,數(shù)據(jù)壓縮等等。
封裝不同:
??Retrofit封裝了具體的請求,線程切換以及數(shù)據(jù)轉(zhuǎn)換。
??OkHttp 是基于Http協(xié)議封裝的一套請求客戶端,雖然它也可以開線程,但根本上它更偏向真正的請求,跟HttpClient, HttpUrlConnection的職責(zé)是一樣的。
網(wǎng)上一般都推薦RxJava+Retrofit+OkHttp框架。