OkhttpClient學(xué)習(xí)

OkHttpClient 學(xué)習(xí)和使用

先通過(guò)一個(gè)非常簡(jiǎn)單的例子來(lái)看怎樣使用OKHttpClient發(fā)送一個(gè)請(qǐng)求,然后根據(jù)這個(gè)簡(jiǎn)單例子來(lái)詳細(xì)的分析每個(gè)步驟拾给。

        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Request request = new Request.Builder().url("http://www.baidu.com").build();
        Response response = client.newCall(request).execute();
        ResponseBody responseBody = response.body();

這是一個(gè)通過(guò)OkHttpClient發(fā)送一個(gè)簡(jiǎn)單的get請(qǐng)求百度首頁(yè)的過(guò)程祥得。

  1. 創(chuàng)建一個(gè)OkHttpClient實(shí)例
  2. 創(chuàng)建一個(gè)Request實(shí)例
  3. 使用 OkHttpClient 創(chuàng)建一個(gè)Call并執(zhí)行 execute()方法臼予,得到一個(gè)Response對(duì)象。
  4. 對(duì)Response 進(jìn)行相關(guān)操作啃沪。

以上就是整個(gè)簡(jiǎn)單HTTP請(qǐng)求的發(fā)送和接收過(guò)程。

OkHttpClient實(shí)現(xiàn)了CloneableCall.Factory接口窄锅,Cloneable接口表示okhttpclient支持Object的clone方法创千。Call.Factory接口是通過(guò)Request創(chuàng)建一個(gè)Call。同時(shí)也要實(shí)現(xiàn)Call.FactorynewCall方法入偷。
OkHttpClient通過(guò)內(nèi)部的Builder類來(lái)創(chuàng)建追驴。生成器模式,new OkHttpClient(){ this(new Builder())} 或者new OkHttpClient.Builder().build().創(chuàng)建OkHttpClient的方式比較多疏之,這樣都是使用默認(rèn)的OkHttpClient的配置殿雪。
相關(guān)可以配置的和Client相關(guān)的還有

  private static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
      Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1);
    //默認(rèn)支持的協(xié)議
  private static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
      ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT);
  //使用https的版本和密碼套件
  final Dispatcher dispatcher;//調(diào)度,異步請(qǐng)求
  final Proxy proxy;//代理 java.net
  final List<Protocol> protocols;
  final List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors;//攔截器
  final List<Interceptor> networkInterceptors;//網(wǎng)絡(luò)攔截器
  final ProxySelector proxySelector;//代理選擇器
  final CookieJar cookieJar;//http cookies 管理方案和 持久化
  final Cache cache;//緩存
  final InternalCache internalCache;//內(nèi)部緩存
  final SocketFactory socketFactory;//socket 工廠 java.net
  final SSLSocketFactory sslSocketFactory; //SSLSocket 工廠 java.net.ssl 
  final CertificateChainCleaner certificateChainCleaner;//證書方案
  final HostnameVerifier hostnameVerifier;//hostName 校驗(yàn) OkHostnameVerifier
  final CertificatePinner certificatePinner;//固定的證書
  final Authenticator proxyAuthenticator;//代理的身份認(rèn)證
  final Authenticator authenticator;// web的身份認(rèn)證
  final ConnectionPool connectionPool;//連接池
  final Dns dns;//DNS
  final boolean followSslRedirects;//是否 執(zhí)行 ssl redirect
  final boolean followRedirects;//是否執(zhí)行 redirect
  final boolean retryOnConnectionFailure; //連接失敗后是否重試
  final int connectTimeout;//連接超時(shí)時(shí)間
  final int readTimeout;// 讀取超時(shí)
  final int writeTimeout;// 寫入超時(shí)

Request和Client一樣也是使用生成器模式完成的锋爪。
Request中包含了

  private final HttpUrl url;
  private final String method;
  private final Headers headers;
  private final RequestBody body;
  private final Object tag;

  private volatile CacheControl cacheControl; // Lazily initialized.

Request 中包含的內(nèi)容都是比較清晰的丙曙,一個(gè)是HttpUrl對(duì)象。主要內(nèi)容就是請(qǐng)求地址其骄,實(shí)例化的時(shí)候可以指定亏镰,協(xié)議,端口等拯爽。method就是指請(qǐng)求方法索抓,Headers是請(qǐng)求頭的封裝。RequestBody就是請(qǐng)求主體毯炮。

HttpUrl 的使用

    HttpUrl url = new HttpUrl.Builder()
        .scheme("https")
        .host("www.baidu.com")
        .addPathSegment("s")
        .addQueryParameter("wd", "dota2")
        .build();
    System.out.println(url);
 //  https://www.baidu.com/s?wd=dota2

得到了一個(gè)HttpUrl逼肯。還有很多其他的方法:
queryParameterName()queryParameterValue 獲取get請(qǐng)求參數(shù) 等。

RequestBody是一個(gè)抽象類桃煎。還有兩個(gè)子類FormBodyMultipartBody篮幢。主要差別在于MediaType.
回到例子中的Request對(duì)象,使用了默認(rèn)的Request.Builder()來(lái)構(gòu)建为迈。默認(rèn)的是get方法洲拇,默認(rèn)的Header.Builder。tag默認(rèn)是自身曲尸。

OkHttpClient 實(shí)現(xiàn)了Call.Factory接口赋续,創(chuàng)建一個(gè)Call

public Call newCall(Request request) {
    return new RealCall(this, request);
  }

實(shí)際上接下來(lái)的工作都是由RealCall在完成的另患。
根據(jù)client和request創(chuàng)建一個(gè)RealCall實(shí)例纽乱,client被final修飾。默認(rèn)會(huì)加上RetryAndFollowUpInterceptor參數(shù)昆箕。

  protected RealCall(OkHttpClient client, Request originalRequest) {
   this.client = client;
   this.originalRequest = originalRequest;
   this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
 }

然后就是execute()

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }
  1. 檢查這個(gè)Call是否被執(zhí)行過(guò)
  2. 利用client.dispatcher.execute(this)來(lái)完成實(shí)際的請(qǐng)求過(guò)程鸦列。Dispatcher在client文檔中的表示的是異步請(qǐng)求的調(diào)度租冠。實(shí)際上同步請(qǐng)求也是通過(guò)他們來(lái)調(diào)度完成的
  3. Reqsponse是通過(guò)getResponseWithInterceptorChain()方法獲得的。從方法名可知薯嗤,會(huì)通過(guò)一系列的攔截器顽爹。
  4. 最后通知dispatcher執(zhí)行完成。

具體的Dispatcher稍后看骆姐,先關(guān)注發(fā)送請(qǐng)求解析返回結(jié)果的getResponseWithInterceptorChain()镜粤。

  private Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

這個(gè)方法把網(wǎng)絡(luò)請(qǐng)求,重試玻褪,緩存肉渴,壓縮等操作都統(tǒng)一成一個(gè)個(gè)Interceptor。形成一個(gè)Interceptor.Chain带射,最后完成一次請(qǐng)求的過(guò)程同规。

通過(guò)getResponseWithInterceptorChain()可以看出Interceptor.Chain的組成部分:

  1. client.interceptors 構(gòu)造client的時(shí)候設(shè)置的Interceptors
  2. retryAndFollowUpInterceptor負(fù)責(zé)失敗重試和重定向。this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);在構(gòu)造RealCall時(shí)創(chuàng)建窟社。
  3. 橋接券勺,將請(qǐng)求轉(zhuǎn)換成發(fā)送到服務(wù)器的請(qǐng)求、通過(guò)網(wǎng)絡(luò)響應(yīng)構(gòu)造一個(gè)服務(wù)器的返回響應(yīng)d的BridgeInterceptor灿里。
  4. 讀取緩存返回朱灿,更新緩存的CacheInterceptor
  5. 和服務(wù)器創(chuàng)建連接的ConnectInterceptor钠四。
  6. CallServerInterceptor makes a network call to the server 最后一個(gè)Interceptor.
    然后創(chuàng)建一個(gè)Interceptor.Chain 實(shí)例盗扒,執(zhí)行proceed方法。得到Response.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缀去,一起剝皮案震驚了整個(gè)濱河市侣灶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缕碎,老刑警劉巖褥影,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咏雌,居然都是意外死亡凡怎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門赊抖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)统倒,“玉大人,你說(shuō)我怎么就攤上這事氛雪》看遥” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浴鸿。 經(jīng)常有香客問(wèn)我井氢,道長(zhǎng),這世上最難降的妖魔是什么岳链? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任花竞,我火速辦了婚禮,結(jié)果婚禮上掸哑,老公的妹妹穿的比我還像新娘约急。我一直安慰自己,他們只是感情好举户,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著遍烦,像睡著了一般俭嘁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上服猪,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天供填,我揣著相機(jī)與錄音,去河邊找鬼罢猪。 笑死近她,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的膳帕。 我是一名探鬼主播粘捎,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼危彩!你這毒婦竟也來(lái)了攒磨?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤汤徽,失蹤者是張志新(化名)和其女友劉穎娩缰,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谒府,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拼坎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了完疫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泰鸡。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖壳鹤,靈堂內(nèi)的尸體忽然破棺而出鸟顺,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布讯嫂,位于F島的核電站蹦锋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏欧芽。R本人自食惡果不足惜莉掂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望千扔。 院中可真熱鬧憎妙,春花似錦、人聲如沸曲楚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)龙誊。三九已至抚垃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趟大,已是汗流浹背鹤树。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逊朽,地道東北人罕伯。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像叽讳,于是被迫代替她去往敵國(guó)和親追他。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • OkHttp源碼的samples的簡(jiǎn)單使用的示例: public static void main(String....
    _warren閱讀 747評(píng)論 0 1
  • 這篇文章主要講 Android 網(wǎng)絡(luò)請(qǐng)求時(shí)所使用到的各個(gè)請(qǐng)求庫(kù)的關(guān)系岛蚤,以及 OkHttp3 的介紹湿酸。(如理解有誤,...
    小莊bb閱讀 1,159評(píng)論 0 4
  • OkHttp解析系列 OkHttp解析(一)從用法看清原理OkHttp解析(二)網(wǎng)絡(luò)連接OkHttp解析(三)關(guān)于...
    Hohohong閱讀 20,974評(píng)論 4 58
  • OkHttp源碼分析-同步篇 很早就想拿okhttp開(kāi)刀了灭美,這次就記一次使用OKhttp的網(wǎng)絡(luò)請(qǐng)求推溃。首先需要說(shuō)明的...
    埃賽爾閱讀 981評(píng)論 1 2
  • 小翠是我一個(gè)辦公室的同事,最近被她父親氣的要死届腐。 小翠父親六十出頭铁坎,身體硬朗,和老伴一起經(jīng)營(yíng)幾畝地犁苏,過(guò)著自給自足的...
    家里真好閱讀 2,590評(píng)論 21 76