Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> OkHttp完全解析

OkHttp完全解析

編輯:關於Android編程

然後直接進入正題。

看完上面這篇文章,主要理解的幾個點:

外部通過構造Request,初始化OkHttpClient,並由兩者共同構造出Call。 訪問網絡通過Call,Call支持兩種模式:同步和異步。同步使用execute,該方法會立即返回一個response,該response中包含結果。異步使用enqueue,也要傳入callback來接受請求結果。 OkHttp還支持攔截器,攔截器分兩種,請求前攔截和網絡返回前攔截。 OkHttp還支持host檢查、證書檢查等等。並且還支持http1.0、http1.1、http2.0、SPDY協議。

先給一張關系圖,嘔心瀝血之作。(這圖請放大看)
這裡寫圖片描述vcfrx/O1xMfpv/ajqMbkyrXNrLK90uyyvcO7x/ix8MCyo6mjrLj5vt3V4tXFzbzAtL2yveLSu7j2x+vH87XEwfezzKGjPC9wPg0KPHA+z8jAtL+0z8JSZXF1ZXN0o6zV4rj2wODA78Pmuty88rWlo6zWu8rHvMfCvMHL0rvQqbv5sb61xLLOyv2jrMD9yOd1cmyhom1ldGhvZKGiaGVhZGVyoaJyZXF1ZXN0Qm9kebXI0MXPoqGjPC9wPg0KPHA+1Nm/tM/CT2tIdHRwQ2xpZW501eK49sDgo6zV4rj2wO/D5tKyuty88rWlo6zDu9PQyrLDtLi01NO1xMLfvK2jrNa7ysfSu7j21tDXqtW+oaPU2tXiuPbA78PmvMfCvMHL0rvQqcirvta1xLarzvejqLWxyLtPa0h0dHBDbGllbnTV4rj20rLKx8irvtbOqNK7tcSjrLWrsrvKx7WlwP2jrMTjv8nS1LS0vai24Lj2T2tIdHRwQ2xpZW50o6yyu82stcTH68fz1Nqyu82stcRPa0h0dHBDbGllbnTW0KOsubLP7bXE18rUtNKysrvSu9H5o6zA/cjnz8LD5szhtb21xNK70KnXytS0o6mjrMD9yOc8Y29kZT5MaXN0PGludGVyY2VwdG9yPqOosPzAqMfrx/PHsLrNt7W72MewtcTAub3Yo6mjrENhY2hlz+C52LXE0rvQqcDgoaJDb25uZWN0aW9uUG9vbKOsu7nT0NK70Kmwssirt73D5rXEwOCjrMD9yOdTb2NrZXRGYWN0b3J5oaJTb2NrZXRTU0xGYWN0b3J5oaJUcnVzdFJvb3RJbmRleKOo0enWpMrpo6mhokhvc3RuYW1lVmVyaWZpZXKhokNlcnRpZmljYXRlUGlubmVytciho0Nvbm5lY3Rpb25Qb29s1eK49rrc1tjSqqOsv7TD+9fWvs3WqrXA1eLKx8GsvdOz2KOs1vfSqtPDwLS05rfFtbHHsLSm09rBrL3T17TMrLXEuPe49mNvbm5lY3Rpb26jrLrNz9+zzLPYysfSu7j2uMXE7qGjtbHQ6NKqzfjC58GsvdPKsaOsu+HPyLTTuMNwb29s1tDIobXD0ru49mNvbm5lY3Rpb26jrNXiuPbJ1Lrzu+G8zND4veLKzaOs1N3Ksc/I1eLDtMDtveKho0Nvbm5lY3Rpb25Qb29s1rvT0NTaT2tIdHRwQ2xpZW50wO/D5rP1yry7r6OssqLH0sirvtbS/dPDtb1jb25uZWN0aW9uUG9vbLa8tNNPa0h0dHBDbGllbnTW0NL908OhozwvaW50ZXJjZXB0b3I+PC9jb2RlPjwvcD4NCjxwPjxjb2RlPrv5sb7By73izerV4rj2wODWrrrzo6zAtL+0z8LI57rOubnU7LP2Y2FsbKOstffTw7XEysdPa0h0dHBDbGllbnQubmV3Q2FsbCguLim3vbeoo7o8L2NvZGU+PC9wPg0KPHByZSBjbGFzcz0="brush:java;"> @Override public Call newCall(Request request) { return new RealCall(this, request); }

該方法返回的是RealCall對象,RealCall是接下來需要介紹的一個類,這個類是繼承自Call。該類記錄了初始傳進來的request,還有HttpEngine(這裡暫時理解為網絡訪問的入口,通過HttpEngine來建立連接並返回數據)。剛剛提到了RealCall同步執行execute會立即返回一個response:

@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(false);
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

看Response result = getResponseWithInterceptorChain(false);這句,這裡需要說明下剛剛提到的攔截器,攔截器分為請求前和返回前攔截,所以這裡是請求前攔截。看下getResponseWithInterceptorChain(..)這個函數:

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
}

這個函數很簡單,創建了一個攔截器鏈,來處理這個請求。
這裡先解釋下攔截器Interceptor和攔截器鏈Chain:

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}

攔截器的接口很簡單,只有一個intercept方法,用來處理該攔截器想要如何處理請求。Chain的接口也很簡單,request方法該鏈中被處理的請求。proceed也很簡單,返回當前被處理後的response。至於最後個方法,暫時不清楚。所以Chain的作用就是讓request從頭至尾經歷攔截器的Intercept方法。
在上面方法中,創建的是ApplicationInterceptorChain這個鏈,讓我們看下這個鏈proceed的具體實現:

@Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        Interceptor interceptor = client.interceptors().get(index);
        Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      return getResponse(request, forWebSocket);
    }

這個方法中就是遍歷client中所有的intercepts(請求前攔截),這裡要注意的是client中的攔截器是每個request都要經歷的。當走完所有的攔截器後,就去調用getResponse訪問網絡。看下getResponse中具體的實現:

Response getResponse(Request request, boolean forWebSocket) throws IOException {
    // Copy body metadata to the appropriate request headers.
    RequestBody body = request.body();
    if (body != null) {
      Request.Builder requestBuilder = request.newBuilder();

      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }

      request = requestBuilder.build();
    }

    // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
    engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

    int followUpCount = 0;
    while (true) {
      if (canceled) {
        engine.releaseStreamAllocation();
        throw new IOException("Canceled");
      }

      boolean releaseConnection = true;
      try {
        engine.sendRequest();
        engine.readResponse();
        releaseConnection = false;
      } catch (RequestException e) {
        // The attempt to interpret the request failed. Give up.
        throw e.getCause();
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        HttpEngine retryEngine = engine.recover(e.getLastConnectException(), null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }
        // Give up; recovery is not possible.
        throw e.getLastConnectException();
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        HttpEngine retryEngine = engine.recover(e, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }

        // Give up; recovery is not possible.
        throw e;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          StreamAllocation streamAllocation = engine.close();
          streamAllocation.release();
        }
      }

      Response response = engine.getResponse();
      Request followUp = engine.followUpRequest();

      if (followUp == null) {
        if (!forWebSocket) {
          engine.releaseStreamAllocation();
        }
        return response;
      }

      StreamAllocation streamAllocation = engine.close();

      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (!engine.sameConnection(followUp.url())) {
        streamAllocation.release();
        streamAllocation = null;
      }

      request = followUp;
      engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
          response);
    }
  }

該方法中首先是根據request中的參數重新構建一個request,在request的頭部中加入了一些參數。然後就根據HttpEngine來訪問網絡了。
首先根據request和OkHttpClient創建了一個HttpEngine(當然還有其他的參數,稍後解釋),然後就進入了一個while(true)的循環。這個循環中先判斷該request是不是被cancel了。然後就調用了HttpEngine的sendRequest方法(後面講解,這理解為就是發送請求),然後在調用HttpEngine的readResponse方法來讀取訪問結果。如果訪問時發生了錯誤,例如RouteException、IOException,則會嘗試重連,調用HttpEngine的recover方法,重新生成一個HttpEngine來訪問,然後重新進入剛剛的循環。如果訪問成功,則調用getResponse方法來獲取訪問結果,調用followUpRequest來獲取重定向請求,這裡需要了解下重定向的概念。
一個簡單的重定向例子就是一個網站,登陸的用戶分為兩種:管理員和游客,同一個url,對於不同身份的人來說訪問到的頁面可能不一樣,這裡就是用了重定向功能,例如該網站的某個頁面,如果管理員訪問是長某某樣子(網頁A),游客訪問是長某某樣子(網頁B),這兩個網頁對應的url也不同,但是初始訪問的url都是一樣的,這是通過服務器對url和用戶解析,返回一個新的url讓用戶去訪問。不知道這麼講大家懂了沒。。。一個簡單的請求,重定向可以多次,不同的浏覽器支持不同的次數。OkHttp框架中重定向最大次數由HttpEngine.MAX_FOLLOW_UPS決定:
這裡寫圖片描述
回到正題,剛剛講到如果訪問成功,則調用getResponse方法來獲取訪問結果,調用followUpRequest來獲取重定向請求。這裡要了解的是,如果服務器發現要重定向,此次response還是返回200(代表成功),在response中還會包含下個重定向的url等信息。所以拿到response前需要檢測是否需要重定向,如果要重定向還要檢測是否超過最大值,因為剛剛說到這是在一個while(true)的循環裡,重定向可能多次。如果發現followUpRequest為空,則說明response已拿到,直接返回。若不為空,則先檢測是否超過最大值,若不超過,則新生成一個httpEngine來訪問。
上面這段代碼基本講解完畢,但是在代碼中,還看到一個概念StreamAllocation,將這個詞分開來看,stream和allocation。解釋下stream,是流的概念,和我們平時用InputStream和outputStream是一樣的概念,我不知道該怎麼解釋http中的stream,就暫且把stream看成是一個請求在http中輸入輸出的流,一個stream代表一個請求。allocation比較簡單,就是分配的概念,合起來看的話就是記錄一個stream分配。StreamAllocation是一個比較重要的概念,首先先要了解下http版本。
http版本從最初的1.0版本,到後續的1.1版本,再到後續Google推出了SPDY,後來在推出了2.0版本,http協議越來越完善,下面幾篇資料是講述http協議的一個發展以及優化的過程。
HTTP1.0和HTTP1.1的區別 ———- http://blog.csdn.net/elifefly/article/details/3964766/
HTTP2.0的講解 ———- http://www.open-open.com/lib/view/open1455796649605.html
HOL排頭阻塞(head of line blocking) – http://baike.baidu.com/link?url=o2BnfuFRd-5jaIlcfAPMolg8nU-U4FUcjlK3jBA9PqI8iffnw3Q7nqx4EzNnjp9BKQDrTWuHFhLGquwxCH1DIa
socket講解————–http://blog.csdn.net/semillon/article/details/7515926

上面這幾篇文章一定要看,特別是http2.0的講解和socket講解這篇文章,閱讀完該篇文章才能理解後續的講解以及OkHttp設計的一個思想。
看完上述幾篇文章,主要的一個核心思想就是http2.0和http1.0/1.1的主要區別,而OkHttp也是根據2.0和1.0/1.1作為區分,實現了兩種連接機制。2.0解決了老版本(後續成1.0和1.1為老版本)最重要的兩個問題:連接無法復用和head of line blocking問題。2.0使用了多路復用的技術,多個stream可以共用一個tcp連接,每個tcp連接都是通過一個socket來完成的,socket對應一個host和一個port,如果有多個stream(也就是多個request)都是連接到同一個host和port上,那麼他們就可以共同使用一個socket。這樣做的好處是減少TCP的一個三次握手的時間。 那在OkHttp裡,記錄一次連接的是RealConnection,這個就是負責連接的,在這個類中用socket來連接,還有HandShake來處理握手。

這裡要說明下,OkHttp和HttpUrlConnection以及Volley的區別。雖然這三個都是可以用來訪問網絡的,但是還是不同的。我們最熟悉的肯定是HttpUrlConnection,這是google官方提供的用來訪問網絡,但是HttpUrlConnection實現的比較簡單,只支持1.0/1.1,並沒有上面講的多路復用,如果碰到app大量網絡請求的時候,性能比較差,而且HttpUrlConnection底層也是用Socket來實現的。而Volley是一個開源庫,它只是封裝了訪問網絡的一些操作,但是底層還是使用HttpUrlConnection。但是OkHttp不同,在看源碼之前,一直以為OkHttp和Volley一樣,是用HttpUrlConnection,但是找了半天代碼,都沒看到HttpUrlConnection和InputStream(OutputStream),倒是反而看到socket和sink(source)這些,後來才搞明白,原來OkHttp像HttpUrlConnection一樣,實現了一個網絡連接的過程。所以按照層級來說,OkHttp和HttpUrlConnection是一級的,用socket實現了網絡連接,只是OkHttp更強大,而Volley只是一個引用了HttpUrlConnection,它並不關心網絡連接過程,只是封裝了請求的過程而已。剛剛提到HttpUrlConnection在IO方面用到的是InputStream和OutputStream,但是OkHttp用的是sink和source,這兩個是在Okio這個開源庫裡的,sink相當於outputStream,source相當於是inputStream。sink和source比InputStream和OutputStream更加強大,單拿sink舉例,他的子類有BufferedSink(支持緩沖)、GzipSink(支持Gzip壓縮)、ForwardingSink和InflaterSink(後面這兩者服務於GzipSink),source對應的也有,具體的可以自行上網查找。

剛剛我們講到多個相同host和port的stream可以共同使用一個socket,而RealConnection就是處理連接的,那也就是說一個RealConnection上可能有很多個Stream,所以在RealConnection上記錄了List> allocations = new ArrayList<>(); 而StreamAllocation就是記錄當前這個Stream是被分配到哪個RealConnection上,所以在StreamAllocation裡也有一個變量記錄了哪個RealConnection上。當然,每次生成一個RealConnection都要放入ConnectionPool裡面,方便新的請求到達後,若能復用則復用池裡的connection。
再回到剛剛那個函數的最後一點代碼:

if (!engine.sameConnection(followUp.url())) {
    streamAllocation.release();
    streamAllocation = null;
}

request = followUp;
engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,response);

當發現需要重定向的時候,就會執行這段代碼,首先先檢測重定向的url和剛剛的請求是不是同一個Connection,看下sameConnection函數:

public boolean sameConnection(HttpUrl followUp){
    HttpUrl url = userRequest.url();
    return url.host().equals(followUp.host())
        && url.port() == followUp.port()
        && url.scheme().equals(followUp.scheme());
}

這函數很簡單,只是看下這兩個url的host、port、scheme是不是一樣。如果發現不一樣,就釋放HttpEngine原來的streamAllocation,並置空,如果發現一樣,則重用剛剛的stream。HttpEngine的構造函數裡面會判斷傳入的StreamAllocation是不是為空,若為空則創建一個根據request,並傳入ConnectionPool,創建一個streamAllocation,並且從ConnectionPool中取出Connection,並將該Connection記錄到StreamAllocation中,如果沒有可用的RealConnection,就創建個新的,然後再放到ConnectionPool中。

講到這裡,應該還是比較清楚的,目前已經講清楚幾個類了:OkHttpClient、RealCall、StreamAllocation、RealConnection、ConnectionPool。
接下來看下HttpEngine。這個類還是比較復雜的,剛剛在RealCall中只是看到調用了HttpEngine的一些函數,大致明白這些函數的意義,那現在繼續看看這些函數內部實現。
先看下sendRequest函數:

public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();

    Request request = networkRequest(userRequest);

    InternalCache responseCache = Internal.instance.internalCache(client);
    Response cacheCandidate = responseCache != null
        ? responseCache.get(request)
        : null;

    long now = System.currentTimeMillis();
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;

    if (responseCache != null) {
      responseCache.trackResponse(cacheStrategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }

    // If we're forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
      userResponse = new Response.Builder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(EMPTY_BODY)
          .build();
      return;
    }

    // If we don't need the network, we're done.
    if (networkRequest == null) {
      userResponse = cacheResponse.newBuilder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .cacheResponse(stripBody(cacheResponse))
          .build();
      userResponse = unzip(userResponse);
      return;
    }

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean success = false;
    try {
      httpStream = connect();
      httpStream.setHttpEngine(this);

      if (writeRequestHeadersEagerly()) {
        long contentLength = OkHeaders.contentLength(request);
        if (bufferRequestBody) {
          if (contentLength > Integer.MAX_VALUE) {
            throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                + "setChunkedStreamingMode() for requests larger than 2 GiB.");
          }

          if (contentLength != -1) {
            // Buffer a request body of a known length.
            httpStream.writeRequestHeaders(networkRequest);
            requestBodyOut = new RetryableSink((int) contentLength);
          } else {
            // Buffer a request body of an unknown length. Don't write request headers until the
            // entire body is ready; otherwise we can't set the Content-Length header correctly.
            requestBodyOut = new RetryableSink();
          }
        } else {
          httpStream.writeRequestHeaders(networkRequest);
          requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
        }
      }
      success = true;
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (!success && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
  }

代碼還是很長的,先來看下第五行,先是調用了一個networkRequest返回了一個request,這個函數就是對原來我們外部傳進去的request做了一個封裝,封裝成一個真正訪問網絡請求的request。在HttpEngine中有兩個request,一個叫userRequest,一個是networkRequest,第一個是外部傳入的,未經OkHttp修改的,第二個是根據userRequest封裝的一個request,用來訪問網絡。接下來就是獲取InternalCache,Internal.instance是一個單例,該單例初始化是在OkHttpClient裡面,可以看到調用Internal.instance.internalCache(client)函數只是調用了client(OkHttpClient)的internalCache,這個函數是返回了我們傳入OkHttpClient的cache,如果你創建OkHttpClient的時候,沒有傳入,那麼這裡就會返回空。
得到了InternalCache後,嘗試根據request去獲取response,當然可能為空。接下來就到CacheStrategy了,CacheStrategy是一個決定訪問網絡還是訪問緩存的類。CacheStrategy.Factory是工廠類,通過傳入request和剛剛internalCache中獲取到的response,去get一個CacheStrategy,Factory.get函數主要是對request和response做了一個檢查,會根據response合不合法、是否過期、request的參數來判斷,最後返回一個CacheStrategy。CacheStrategy很簡單,裡面有兩個變量,一個是networkRequest,一個是cacheResponse(這個變量和傳入Factory的response可能是不一樣的哦!)。返回到剛剛的HttpEngine.sendRequest函數中看第17行,如果InternalCache不為空,就調用trackResponse,這個函數很簡單,就是記錄下緩存讀取命中率這些數據。然後如果從InternalCache中response不為空,但是cacheStrategy的response為空,則說明剛剛InternalCache取出來的response無效,則需要關掉。如果CacheStrategy的networkRequest不為空,則說明需要進行網絡訪問,如果cacheResponse不為空,則說明訪問緩存足以。根據這個理論,下面一直到第47行的代碼不成問題,就不解釋了。接下來看網絡訪問的部分。
網絡訪問主要是通過HttpStream來實現,HttpStream這是一個接口,裡面定義了一些函數,這些函數是負責讀取網絡數據、輸出數據等。實現該接口的有兩個類,一個是Http2xStream,一個是Http1xStream。第一個是專門負責Http2.0版本的,第二個是負責Http1.x版本的,兩者內部實現機制不一樣。Http2xStream是通過一個FramedConnection,至於對FramedConnection的理解,可以看前面關於Http2.0講解的文章,看完那個你應該比較能夠大概清楚的理解他了,我就不解釋了,這裡我也沒深入去看。而Http1xStream則是通過sink和source來實現的,這個前面講過了,具體自己看吧,不解釋了。
再次返回代碼,connect函數返回了一個HttpStream,看下具體實現:

private HttpStream connect() throws RouteException, RequestException, IOException {
    boolean doExtensiveHealthChecks = !networkRequest.method().equals("GET");
    return streamAllocation.newStream(client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis(),
        client.retryOnConnectionFailure(), doExtensiveHealthChecks);
}

主要還是調用了stream.newStream,接下來的源碼就不看了,實在太多,感覺這篇文章可以繞地球三圈了。
newStream的函數裡面,首先就是去創建一個RealConnection,然後根據返回的RealConnection裡的參數去判斷,如果RealConnection.framedConnection不為空,則返回Http2xStream(這裡面包含connection的framedConnection),如果為空,則返回Http1xStream(這裡包含connection的sink和source),所以這和我前面講到的一樣,RealConnection只是負責連接到服務器,具體的數據傳輸讀取還是通過HttpStream。
那streamAllocation如何創建一個RealConnection呢,這個前面講過,先看看StreamAllocation自己是否已經有一個connection,如果有則返回,若沒有繼續。根據StreamAllocation裡面的address去connectionPool裡面去取Connection,如果發現有則返回,如果沒有就新創建一個,創建之後放入connectionPool中,並連接!!這點很重要,放入連接池的或者已經記錄在StreamAllocation中的都是已連接的。
創建完HttpStream後就是數據流的進行了,後面應該就可以自己看懂了,不解釋了。

如果一個stream結束了,需要release,並且關閉sink和source、framedConnection,還要釋放RealConnection的list的一個,總之就是收尾工作要做好。然後HttpEngine的readResponse也就不解釋了,對了在這裡還有結果返回前的一個攔截,和之前攔截差不多一個原理,也不解釋了。

還有就是Route和RouteDatabase,這兩個類的意思就是記住當前已經走過的彎路,後續不要再走了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved