okhttp3基本使用和源码解析

准备

okhttp官网:http://square.github.io/okhttp/
豆瓣测试接口:https://api.douban.com/v2/movie/top250?start=0&count=10

基础使用

同步方式

GET


        OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250?start=0&count=10").build();

        Call call = mOkHttpClient.newCall(request);
        try {
            Response response = call.execute();
            String stringResponse = response.body().string();
            System.out.println("stringGetResponse ==> " + stringResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }

POST

        OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
        RequestBody mRequestBody = new FormBody.Builder().add("start", "0").add("count", "10").build();
        Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250").post(mRequestBody).build();


        Call call = mOkHttpClient.newCall(request);
        try {
            Response response = call.execute();
            String stringResponse = response.body().string();
            System.out.println("stringPostResponse ==> " + stringResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }

        OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
        RequestBody mRequestBody = new FormBody.Builder().add("start", "0").add("count", "10").build();
        Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250").header("token", "logintoken").post(mRequestBody).build();

        System.out.println("reqstring ==> " +  request.headers().toString() + "__________" +request.header("token").toString());

        Call call = mOkHttpClient.newCall(request);
        try {
            Response response = call.execute();
            String stringResponse = response.body().string();
            System.out.println("stringPostResponse ==> " + stringResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }

Interceptor


        /*************************************************核心代码***********************************************/
        Interceptor interceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                String url = request.url().toString();

                System.out.println("Interceptor url == " + url);

                return chain.proceed(request);
            }
        };

        OkHttpClient mOkHttpClient = new OkHttpClient.Builder().addInterceptor(interceptor).addNetworkInterceptor(interceptor).build();
        /*************************************************核心代码***********************************************/
        Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250?start=0&count=10").build();

        Call call = mOkHttpClient.newCall(request);
        try {
            Response response = call.execute();
            String stringResponse = response.body().string();
            System.out.println("stringGetResponse ==> " + stringResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }

异步方式

GET


    OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
            Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250?start=0&count=10").build();

            Call call = mOkHttpClient.newCall(request);

            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    System.out.println("stringGetResponse ==> onFailure");
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String stringResponse = response.body().string();
                    System.out.println("stringGetResponse ==> " + stringResponse);
                }

            });

POST


        OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
        RequestBody mRequestBody = new FormBody.Builder().add("start", "0").add("count", "10").build();
        Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250").post(mRequestBody).build();


        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("stringPostResponse ==> onFailure" + "");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String stringResponse = response.body().string();
                System.out.println("stringPostResponse ==> " + stringResponse);
            }
        });

1.OkHttp中的拦截器分2个:APP层面的拦截器(Application Interception)、网络请求层面的拦截器(Network Interception)。
2.OkHttp的拦截器是在OkHttp2.2之后才可以使用,并且拦截器不能与Retrofit ≤ 1.8和Picasso ≤ 2.4框架同时使用。
3.OkHttp使用列表来跟踪拦截器,并按顺序调用拦截器。

源码解析

Dispatcher

先说一下,这个框架内有个很重要的东西叫做Dispatcher,意为调度器,我们先看下他在哪儿定义的。

Dispatcher的初始化

     OkHttpClient.java内定义的,通过builder.dispatcher对其进行赋值

     OkHttpClient(Builder builder) {
        ......
        this.dispatcher = builder.dispatcher;
        ......
     }
     OkHttpClient.builder是OkHttpClient一个静态内部类,在其构造内进行了初始化

     OkHttpClient {
         ......
         public static final class Builder {
             public Builder() {
                ......
                dispatcher = new Dispatcher();
                ......
             }
         }
     }
      我们一般在我们的业务类里边初始化的时候是这么new出来的。到这里相当于就初始化了这个Builder。

      OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();

Dispatche初步分析

先来看看定义了些啥:


public final class Dispatcher {

      private int maxRequests = 64;//最大并发请求数为64
      private int maxRequestsPerHost = 5;//每个主机最大请求数为5

      private @Nullable Runnable idleCallback;//执行的任务

      /** Executes calls. Created lazily. */
      private @Nullable ExecutorService executorService;//线程池

      /** 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<>();

      ......

}

HttpClient到Dispatcher的切入点

   Call call = mOkHttpClient.newCall(request);

   call.enqueue(new Callback() {  ......  });

抵达Call的enqueue,而Call是个抽象类,于是进入到了RealCallenqueue

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

看最后一行:

client.dispatcher().enqueue(new AsyncCall(responseCallback));

再到dispatcher的enqueue

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  • 可以看到入参为一个异步AsyncCall。
  • if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost),如果运行队列内的线程数小于最大线程数,并且,主机数小于最大主机阈值,则runningAsyncCalls.add(call); executorService().execute(call);加入运行队列,并命令线程池去执行这几个任务。
  • 这里的AsyncCall是个Runnable子类,所以能被Excutor线程池执行。executorService方法是拿到一个单例线程池executorService

关于请求响应的回调

final class RealCall implements Call {
     ......

     final class AsyncCall extends NamedRunnable {
           private final Callback responseCallback;

           AsyncCall(Callback responseCallback) {
              super("OkHttp %s", redactedUrl());
              this.responseCallback = responseCallback;
           }
     }

}

    /*
     * Copyright (C) 2014 Square, Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package okhttp3;

    import java.io.IOException;

    public interface Callback {
      /**
       * Called when the request could not be executed due to cancellation, a connectivity problem or
       * timeout. Because networks can fail during an exchange, it is possible that the remote server
       * accepted the request before the failure.
       */
      void onFailure(Call call, IOException e);

      /**
       * Called when the HTTP response was successfully returned by the remote server. The callback may
       * proceed to read the response body with {@link Response#body}. The response is still live until
       * its response body is {@linkplain ResponseBody closed}. The recipient of the callback may
       * consume the response body on another thread.
       *
       * <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
       * not necessarily indicate application-layer success: {@code response} may still indicate an
       * unhappy HTTP response code like 404 or 500.
       */
      void onResponse(Call call, Response response) throws IOException;
    }

    class AsyncCall{
        @Override protected void execute() {
              boolean signalledCallback = false;
                  try {
                        Response response = getResponseWithInterceptorChain();
                        if (retryAndFollowUpInterceptor.isCanceled()) {
                          signalledCallback = true;
                          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));//回调处
                        } else {
                          signalledCallback = true;
                          responseCallback.onResponse(RealCall.this, response);//回调处
                        }
                  } catch (IOException e) {
                        if (signalledCallback) {
                          // Do not signal the callback twice!
                          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
                        } else {
                          eventListener.callFailed(RealCall.this, e);
                          responseCallback.onFailure(RealCall.this, e);//回调处
                        }
                      } finally {
                        client.dispatcher().finished(this);
                      }
            }
    }

关于3个Deque

      /** 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<>();

前俩个泛型是AsyncCall是异步的队列,后一个泛型是RealCall的是同步的队列,这个Deque是java包中的一个接口,它是这个框架使用生产者消费者模式的一个体现。

看下它的类结构:

那么我们来看下它是怎么实现的:

    dispatcher内new3个是ArrayDeque,内部是一个数组。

    /**
     * Constructs an empty array deque with an initial capacity
     * sufficient to hold 16 elements.
     */
    public ArrayDeque() {
        elements = new Object[16];
    }

本文Demo

https://github.com/zj614android/okhttpDemo

猜你喜欢

转载自blog.csdn.net/user11223344abc/article/details/80394801