Okhttp源码分析(一)

一,概述

1,OkHttpClient对象的创建。 
2,Request 对象的创建。 
3,Call对象的创建 
4,Call的execute方法实现同步请求。 
5,Call的enqueue方法实现异步请求,异步请求是怎么开启的子线程。 

二,OkHttpClient对象的创建

OKHttpClient对象的创建方式有两种。 
第一种是使用构造方法创建对象:

OkHttpClient client = new OkHttpClient();//使用构造方法直接创建OkHttpClient对象。

第二种是使用Builder模式创建对象:

OkHttpClient.Builder builder = new OkHttpClient.Builder();//先创建构建者对象
 builder.connectTimeout(3*1000, TimeUnit.MILLISECONDS);//设置超时时间
 OkHttpClient client = builder.build();//使用构建者创建OkHttpClient对象。

这两种创建模式本质上是一样的。用的是建造者设计模式(builder)

构造方式的源码(本质上还是用的builder,初始化参数是默认的)

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

Builder是OkHttpClient的内部类,创建Builder对象使用的是builder的无参构造方法。主要功能就是进行一些字段的初始化。

三,Request 对象的创建

Request 也是Builder设计模式,

//get请求Request request = new Request.Builder()
                            .url("http://www.baidu.com")
                            .build();

Builder类是Request 的内部类,与OkHttpClient的内部类Builder不是同一个。

下面看Request 的内部类Builder的无参构造原码:Builder对象时默认把请求方式设置为GET

    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

request 可是设置请求头header。有三个方式

 Request request = new Request.Builder()
           .url(url)
           .header("User-Agent",getUserAgent())
           .addHeader("key","value)
           .addHeaders(new Headers.Builder().build())//传递一个headers对象,
.build();
如果传递中文。会报错。因为源码的 checkNameAndValue (String name, String value)对中文进行处理。所以如果传递中文
需要用下面这个方法进行处理
    private static String getUserAgent(   String userAgent) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0, length = userAgent.length(); i < length; i++) {
            char c = userAgent.charAt(i);
            if (c <= '\u001f' || c >= '\u007f') {
                sb.append(String.format("\\u%04x", (int) c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

四,Call对象的创建

创建call对象:

client.newCall(request)

OKHttpClient类的newCall方法的原码:

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

这个方法的作用是创建RealCall对象,并把client对象和request对象都传递过去了。 

1,RealCall是Call接口的实现类,Call调用的方法的实现都在RealCall类中,这个类是关键类。 
2,将client对象和request对象传递给了RealCall对象,这样等于RealCall对象拥有了client的属性值和request对象的属性值。即我们在前面对client设置的属性值和对request设置的属性值都传递到了这个对象中。


五,RealCall的execute方法实现同步请求。

RealCall类的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);
    }
  }

核心代码是:Response result = getResponseWithInterceptorChain()。这个方法中返回的result 即是我们需要的响应数据。

六,RealCall的enqueue方法实现异步请求

RealCall类的enqueue方法的源码:

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

分析: 
1,这里的client就是前面创建的OKHttpClient对象。 
2,client.dispatcher()方法返回Dispatcher对象,这个类成为调度着,这个对象的创建在OKHttpClient的内部类Builder的构造方法中。 
3,重点有两个,一个是Dispatcher的enqueue方法,一个是AsyncCall对象。

下面先看Dispatcher的enqueue方法的源码:

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

这是一个同步方法,核心代码是:executorService().execute(call);

下面首先看executorService()方法的源码:

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

这个方法创建了一个线程池对象,这个线程池的特点是: 
1,核心线程数为0。 
2,最大线程数是Integer的最大值,这里可以理解为无限多。 
3,非核心线程存活时间为60秒。

分析:这个线程池没有核心线程,非核心线程的存活时间只有60秒,所以这个线程池的优点不是特别突出。

下面继续看:executorService().execute(call); 
executorService()返回一个线程池对象,我们知道execute方法接收Runnable对象,Runnable的run方法执行在子线程。下面开下这个call对象。

这个call对象来源于:client.dispatcher().enqueue(new AsyncCall(responseCallback));

下面看AsyncCall类。 
AsyncCall类是RealCall的内部类,AsyncCall继承NamedRunnable类,NamedRunnable又继承Runnable类。在NamedRunnable类中声明了一个抽象方法execute(),且在run方法中调用了。我们由代码executorService().execute(call)知道此时会调用run方法,从而会调用execute方法。 
下面看AsyncCall的execute方法的源码(注意:这个方法执行在子线程):

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          responseCallback.onResponse(RealCall.this, response);
        }
      }
    }

在这个方法中我们看到了熟悉的代码: 
Response response = getResponseWithInterceptorChain(); 
这行代码在同步请求中已经看到过,它是网络请求的核心。到此同步请求和异步请求都殊途同归到了getResponseWithInterceptorChain方法上。不同的是:异步请求是在子线程中调用的getResponseWithInterceptorChain方法。

此外在这儿我们看到了CallBack的onFailure方法和onResponse方法被调用。由于execute方法执行在子线程,所以onFailure方法和onResponse方法都是执行在子线程。

注意事项: 
1,在RealCAll的enqueue方法中通过线程池的方式开启了子线程。 
2,CallBack的onFailure方法和onResponse方法都执行在子线程中,所以在更新UI时还需要跳转到UI线程。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值