OkHttp的请求分为同步请求和异步请求,下面我们先来分析同步请求的执行流程。
首先,看一下OkHttp执行同步请求的简单示例:
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://baidu.com") .build(); Response response; try { response = client.newCall(request).execute(); Log.d(TAG, response.body() != null ? response.body().toString() : null); } catch (IOException e) { e.printStackTrace(); }
第一步,我们new了一个OkHttpClient,使用了默认的构造函数。
public OkHttpClient() { this(new Builder()); }
这里返回了一个new Builder(). 这个大家应该很熟悉,一个Builder模式的写法。跟进源码部分,可以看到它主要做了一些成员变量的初始化工作。比如Dispatcher,是请求分发器,连接池管理的connectionPool, 我们后面将重点分析, 以及一些timeout的设置等。
public Builder() { dispatcher = new Dispatcher(); protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; eventListenerFactory = EventListener.factory(EventListener.NONE); proxySelector = ProxySelector.getDefault(); cookieJar = CookieJar.NO_COOKIES; socketFactory = SocketFactory.getDefault(); hostnameVerifier = OkHostnameVerifier.INSTANCE; certificatePinner = CertificatePinner.DEFAULT; proxyAuthenticator = Authenticator.NONE; authenticator = Authenticator.NONE; connectionPool = new ConnectionPool(); dns = Dns.SYSTEM; followSslRedirects = true; followRedirects = true; retryOnConnectionFailure = true; connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; pingInterval = 0; }
第二步,下面我们看Request的初始化过程
Request request = new Request.Builder() .url("http://baidu.com") .build();
跟进Builder()方法,主要做了两件简单的事,默认为GET方式,初始化了Header,保存头部信息,传入的url String构造HttpUrl对象。
public Builder() { this.method = "GET"; this.headers = new Headers.Builder(); }
再看Build()方法,直接用之前的Builder对象,构造一个request。
public Request build() { if (url == null) throw new IllegalStateException("url == null"); return new Request(this); }
Request(Builder builder) { this.url = builder.url; this.method = builder.method; this.headers = builder.headers.build(); this.body = builder.body; this.tag = builder.tag != null ? builder.tag : this; }第三步,通过下面的方法,得到response
response = client.newCall(request).execute();
我们看看call的创建过程
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
Call是一个接口,RealCall是Call的具体实现。这边直接使用RealCall类的静态方法newRealCall创建了一个RealCall对象
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { // Safely publish the Call instance to the EventListener. RealCall call = new RealCall(client, originalRequest, forWebSocket); call.eventListener = client.eventListenerFactory().create(call); return call; }
代码也比较简单,创建了一个RealCall对象,赋值了一个listener。继续看RealCall的构造方法
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); }
可以看出,RealCall持有了之前构造的client request对象,赋值了一个重定向拦截器,关于拦截器,后面也会具体分析。
最后,执行call.excute()方法,继续看具体实现类RealCall
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); } }
首先,判断了excuted标志位是否为true,因为同一个请求只能执行一次,如果已经执行了 就抛出异常,没执行过,就把标志位置为true。
然后,捕捉call堆栈,并且执行了listener的callStart方法,看一下。
/** * Invoked as soon as a call is enqueued or executed by a client. In case of thread or stream * limits, this call may be executed well before processing the request is able to begin. * * <p>This will be invoked only once for a single {@link Call}. Retries of different routes * or redirects will be handled within the boundaries of a single callStart and {@link * #callEnd}/{@link #callFailed} pair. */ public void callStart(Call call) { }
注释上可以看出,每次执行call的enqueued或execute方法时,就会开启这个listener。往下看核心代码
try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); }首先,执行了dispatcher的exexuted方法,dispatcher是OkHttp的请求分发器,对于同步请求,executed也比较简单,只是把call放入了running这个队列
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
其实Dispatcher的作用,就是维持call请求发给他的状态,然后内部维护了一个线程池,用于执行网络请求。call在执行的过程中,通过dispatcher这个分发器类,把任务推到执行队列当中,进行操作,操作完成,再执行等待队列的任务。Dispatcher是OkHttp的核心之一,后面会具体分析。
接下来我们继续代码,同步请求队列的定义,下面代码中 的第三个。上面两个,一个是异步的就绪队列,一个是异步的执行队列。
/** 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<>();
执行完dispatcher.executed()方法后,会通过getResponseWithInterceptorChain()方法得到response。这个其实是一个拦截器链方法,后面也会具体分析。
最后我们看一下finally方法,他会在请求结束后执行finished方法
void finished(RealCall call) { finished(runningSyncCalls, call, false); } private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) { int runningCallsCount; Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); if (promoteCalls) promoteCalls(); runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } if (runningCallsCount == 0 && idleCallback != null) { idleCallback.run(); } }
可以看出,把我们正在执行的同步请求传入,从当前队列移除同步请求。这边主要第三个参数我们传入的是false,这里是走不到promoteCalls()的,但异步请求会走到这里,到时再分析。然后,计算了目前还在运行的请求。最后两行有一个判断,如果runningCallsCount为0且idleCallback不为null时,运行了idleCallback。
最后,我们总结一下同步请求
1.创建一个OkHttpClient对象
2.构建一个request对象,通过OkHttpClient和Request对象,构建出Call对象
3.执行call的execute方法。