OkHttp源码分析(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wanggang514260663/article/details/86166515

1、Okhttp基本介绍

github地址:https://github.com/square/okhttp
Okhttp具有一些高效的属性:

  • 在HTTP/2支持下,如果网络请求的host是同一个时,允许这些请求公用一个socket。
  • 使用连接池减少网络延时(如果HTTP/2不可用)
  • 透明的GZIP压缩,较少数据流量
  • 缓存网络响应,避免重复网络请求

2、OkHttp的基本使用

2-1、同步请求

Request request = new Request.Builder().get().url(url).build();
OkHttpClient okHttpClient = new OkHttpClient();
try {
    Response response = okHttpClient.newCall(request).execute();
    Log.e("info", "==>" + response.body().string());
} catch (IOException e) {
    e.printStackTrace();
}

2-2、异步调用

okHttpClient.newCall(request).enqueue(Callback callback);

不管是同步调用还是异步调用,response.body().string()方法只调用一次,连续调用会抛出异常。因为string()方法在获取数据的同时,会清空buffer并关闭数据流。

  • Post表单提交
    表单提交主要是请求使用的Request对象是需要使用RequestBody对象封装请求实体。然后在使用Requestpost()方法进行参数的封装传入。
RequestBody requestBody = new FormRequest.Builder().add("", "").build();
Request request = new Request.Builder().get().url(url).post(requestBody).build();
Response response = okHttpClient.newCall(request).execute();

2-3、缓存

Cache cache = new Cache(cacheDirectory, cacheSize)
Response response = okHttpClient.newCall(request).cache(cache).execute();

2-4、拦截器

拦截器主要分为两种:一种是应用拦截器,主要拦截应用层与okhttp之间的网络请求和响应。另一种是网络拦截器,拦截okhttp与网络层之间的网络请求和响应。

3、OkHttp源码分析

3-1、okhttpClient创建

public OkHttpClient() {
 this(new Builder());
}

而在Builder中初始化了使用到的参数,比如dispatcherinterceptorsnetworkInterceptors以及其它等配置参数。之后调用build()方法创建OkHttpClient对象

public OkHttpClient build() {
    return new OkHttpClient(this);
}

3-2、call对象创建

Call call = client.newCall(request);
...
public Call newCall(Request request) {
 return RealCall.newRealCall(this, request, false /* for web socket */);
}

接下来看看RealCall.newRealCall方法是如何创建出来Call

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
   RealCall call = new RealCall(client, originalRequest, forWebSocket);
   call.eventListener = client.eventListenerFactory().create(call);
   return call;
}

默认情况下,这里的eventListener传入的是

public static final EventListener NONE = new EventListener() {};

在看new RealCall调用

//forWebSocket 如果不使用webSocket的话为false
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
   this.client = client;
   this.originalRequest = originalRequest;
   this.forWebSocket = forWebSocket;
   //初始化重试请求拦截器,用户处理失败或者重定向
   this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
   //异步请求超时处理
   this.timeout = new AsyncTimeout() {
       @Override
       protected void timedOut() {
           cancel();
       }
   };
   this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}

3-3、同步调用execute()

public Response execute() throws IOException {
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    captureCallStackTrace();
    //超时计算开始时间
    timeout.enter();
    eventListener.callStart(this);
    try {
        //加入标记数组,方便处理取消,完成等操作
        client.dispatcher().executed(this);
        //通过拦截器链,获取请求结果
        Response result = getResponseWithInterceptorChain();
        if (result == null) throw new IOException("Canceled");
        return result;
    } catch (IOException e) {
        e = timeoutExit(e);
        eventListener.callFailed(this, e);
        throw e;
    } finally {
        client.dispatcher().finished(this);
    }
}

可以发现同步调用的请求结果主要是依赖getResponseWithInterceptorChain得到。

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 (!forWebSocket) {
         //添加用户设置的网络拦截器
         interceptors.addAll(client.networkInterceptors());
     }
     //负责所有的拦截器完成之后,网络请求的发出
     interceptors.add(new CallServerInterceptor(forWebSocket));
     //将添加的拦截器,设置到拦截器链中
     Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
             originalRequest, this, eventListener, client.connectTimeoutMillis(),
             client.readTimeoutMillis(), client.writeTimeoutMillis());
     //启动拦截器
     return chain.proceed(originalRequest);
 }

对于上面的这些拦截器,后面专门针对每一个做详细的介绍。

3-4、异步调用enqueue(Callback callback)

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));
}

主要是调用了Dispatcherenqueue方法。

void enqueue(AsyncCall call) {
  synchronized (this) {
    //线程取消等操作标志位
    readyAsyncCalls.add(call);
  }
  //
  promoteAndExecute();
}

在看看promoteAndExecute方法

//迭代执行调用 
for (int i = 0, size = executableCalls.size(); i < size; i++) {
  AsyncCall asyncCall = executableCalls.get(i);
  //异步调用请求连接,这里传入的executorService是一个线程池
  asyncCall.executeOn(executorService());
}

executorService是用来创建一个线程池

public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

接下来看看executeOn方法,其中关键代码只有一句executorService.execute(this);,其实就是加入线程池调用,这里传入的是AsyncCall继承的是NamedRunnable,而NamedRunnable实现自Runnable对象。在NamedRunnablerun方法中执行了AsyncCallexecute方法。

...
//执行调用链,返回Response
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
    signalledCallback = true;
    //回掉请求失败
    responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
    signalledCallback = true;
    //回掉请求成功
    responseCallback.onResponse(RealCall.this, response);
}
...

这里的responseCallback就是在enqueue时候传入的callback,由于callback是在ui线程中,所以该操作就直接完成了了线程切换操作,返回的结果是在ui线程中。

基本的调用流程在这里就全部完成了,下篇文章将说明下拦截器链中的所有拦截器方法。

猜你喜欢

转载自blog.csdn.net/wanggang514260663/article/details/86166515