String url = “http://wwww.baidu.com”;
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
在上述代码中可以看到几个关键类和作用
- OkHttpClient : 用于创建Call对象,源码注释是Factory for {@linkplain Call calls}
- Request :构建我们的请求。源码注释是An HTTP request。简单直接
- Call :发起我们的http请求
开始分析
OkHttpClient和Request
先看看我们的 OkHttpClient Request
OkHttpClient.java
public OkHttpClient() {
this(new Builder());
}
我们跟进代码可以看到OkHttpClient是一个构建者模式。Request不跟进也可以看到是一个构造者模式。
接下来,我们继续看Call
Call
//OkHttpClient.java
Call newCall(Request request) {
//此处传入我们的OkHttpClient
return RealCall.newRealCall(this, request, false);
}
//RealCall.java
RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
//Transmitter意为发射器,功能挺杂。注释说是OkHttp的应用程序和网络层之间的桥梁
call.transmitter = new Transmitter(client, call);
return call;
}
在这段代码中,我们可以看到我们得到的Call的实例是RealCall。所以我们enqueue()方法的调用实际是RealCall的方法。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException(“Already Executed”);
executed = true;
}
transmitter.callStart();
//从我们之前传入OkHttpClient中获取其中的Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
注意这里有一个Dispatcher。这个类负责我们网络请求的调度策略。在这段代码中我们用AsyncCall封装了我们的Callback。AsyncCall 是一个NamedRunnable。在这个NamedRunnable中封装了我们的execute()
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object… args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
execute()的具体实现如下
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//此处得到我们的需要的网络数据
Response response = getResponseWithInterceptorChain();
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 {
// 此处是请求失败回调
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
在上面这个方法中我们可以看到请求的结果是如何获得,那么这个runnable任务是怎么调度执行的呢?我们就得回过头看看Dispatcher类的enqueue()方法做了啥
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
if (!call.get().forWebSocket) {
//如果有请求同一host的AsyncCall就进行复用
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
推动执行方法
promoteAndExecute();
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//循环收集可以执行的AsyncCall
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // 最大执行的call大于64 跳出
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // 请求同一host的call > 5 跳过
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
//把可以执行的AsyncCall,统统执行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//executorService()返回一个线程池
asyncCall.executeOn(executorService());
}
return isRunning;
}
void executeOn(ExecutorService executorService) {
boolean success = false;
try {
//线程池运行Runnable,执行run,调用前面提到的AsyncCall.execute
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException(“executor rejected”);
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
//失败回调
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
//结束
client.dispatcher().finished(this);
}
}
}
到了这里我们的AsyncCall就顺利执行了。整个Okhttp代码的主干就在这里。接下来我们继续探讨okhttp这个框架的一些细节设计
拦截器链
前边得到Response的地方,我们调用了getResponseWithInterceptorChain()。但没细讲,这个部分就是大名鼎鼎的okhttp的拦截器链。
//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
List interceptors = new ArrayList<>();
//添加自定义拦截器
interceptors.addAll(client.interceptors());
//添加默认拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//添加自定义网络拦截器(在ConnectInterceptor后面,此时网络连接已准备好)
interceptors.addAll(client.networkInterceptors());
}
//添加默认拦截器,共4+1=5个
最后附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)
面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。
这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…
由于篇幅有限,就不做过多的介绍,大家请自行脑补
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…
由于篇幅有限,就不做过多的介绍,大家请自行脑补
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!