(十九)okhttp框架面試問題

一、okhttp使用簡介

1.創(chuàng)建一個OkHttpClient對象

2.創(chuàng)建一個request對象,通過內(nèi)部類Builder調(diào)用生成Request對象

3.創(chuàng)建一個Call對象,調(diào)用execute(同步)/enqueue(異步)

4.返回Response對象,對Response對象進行處理

    //第一步
    private final OkHttpClient client = new OkHttpClient();

    //第二步
    Request request = new Request.Builder()
            .url("http://www.baidu.com").build();

    //同步請求
    public void okHttpAsycGet() throws IOException {
        //第三步
        Response response = client.newCall(request).execute();

        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
        System.out.println(response.body().string());
    }

    //異步請求
    public void okHttpSyncGet() throws IOException {
        //第三步
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
                System.out.println(response.body().string());
            }
        });
    }

二、okhttp代碼分析

同步方法代碼分析

在client.newCall(request).execute();代碼中的newCall方法實現(xiàn)如下:

@Override 
public Call newCall(Request request) {
  return new RealCall(this, request, false /* for web socket */);
}

newCall()方法會返回一個RealCall對象,RealCall中的execute()方法實現(xiàn)如下:

@Override 
public Response execute() throws IOException {
    synchronized (this) { //方法檢測,execute()只會執(zhí)行一次
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      client.dispatcher().executed(this); //將RealCall添加到Dispatcher中的同步請求隊列中
      Response result = getResponseWithInterceptorChain(); //獲取Response
      if (result == null) throw new IOException("Canceled");
      return result; //返回Response
    } finally {
      client.dispatcher().finished(this); //通知Dispatcher該RealCall已執(zhí)行完
    }
  }

其中的獲取Response的關(guān)鍵方法getResponseWithInterceptorChain()實現(xiàn)如下:

Response getResponseWithInterceptorChain() throws IOException {
  // Build a full stack of interceptors.
  List<Interceptor> interceptors = new ArrayList<>(); //攔截器棧
  interceptors.addAll(client.interceptors()); //添加client中的所有攔截器
  interceptors.add(retryAndFollowUpInterceptor); //失敗重試攔截器
  interceptors.add(new BridgeInterceptor(client.cookieJar())); //橋接攔截器
  interceptors.add(new CacheInterceptor(client.internalCache())); //緩存攔截器
  interceptors.add(new ConnectInterceptor(client)); //與服務(wù)器進行連接的攔截器
  if (!forWebSocket) {
    interceptors.addAll(client.networkInterceptors());  //網(wǎng)絡(luò)攔截器
  }
  interceptors.add(new CallServerInterceptor(forWebSocket)); //網(wǎng)絡(luò)服務(wù)端連接攔截器

  Interceptor.Chain chain = new RealInterceptorChain(
      interceptors, null, null, null, 0, originalRequest); //將攔截器棧連成鏈
  return chain.proceed(originalRequest);
}

異步方法代碼分析

newCall()方法會返回一個RealCall對象,RealCall中的enqueue()方法實現(xiàn)如下:

@Override 
public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

可以看到,方法的最后調(diào)用了Dispatcher的enqueue()方法,該方法的具體實現(xiàn)如下:

/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); //準備中的異步隊列

/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>(); //運行中的異步隊列

/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); //運行中的同步隊列
synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { //若當前正在運行的異步隊列可容納新的任務(wù)
    runningAsyncCalls.add(call); //添加回調(diào)方法到正在運行中的異步隊列
    executorService().execute(call); //使用線程池執(zhí)行該回調(diào)方法
  } else {
    readyAsyncCalls.add(call); //添加回調(diào)方法到準備中的異步方法
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • OkHttp源碼的samples的簡單使用的示例: public static void main(String....
    _warren閱讀 823評論 0 1
  • 這段時間老李的新公司要更換網(wǎng)絡(luò)層,知道現(xiàn)在主流網(wǎng)絡(luò)層的模式是RxJava+Retrofit+OKHttp,所以老李...
    隔壁老李頭閱讀 33,262評論 51 405
  • 這篇文章主要講 Android 網(wǎng)絡(luò)請求時所使用到的各個請求庫的關(guān)系,以及 OkHttp3 的介紹。(如理解有誤,...
    小莊bb閱讀 1,226評論 0 4
  • OkHttp解析系列 OkHttp解析(一)從用法看清原理OkHttp解析(二)網(wǎng)絡(luò)連接OkHttp解析(三)關(guān)于...
    Hohohong閱讀 21,016評論 4 58
  • 2017.11.20星期一,晴,今天有點小暖,正如我和寶貝的心情一樣晴朗,上午家里來了客人,是我的媽媽和舅舅舅媽,...
    張倩與譯丹閱讀 204評論 0 0