目录
1.使用
1)同步请求
2)异步请求
3)提交string
4)提交流
5)提交文件
6)提交表单
7)提交分块请求
8)非系统拦截器
2.解析执行流程
1)OkHttpClient创建
2)Request创建
3)Call创建
4)execute执行
5)enqueue执行
1.使用
依赖: implementation 'com.squareup.okhttp3:okhttp:3.10.0'
1)同步请求
//同步请求
private void sendRequest() {
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.readTimeout(5, TimeUnit.SECONDS)//设置超时...
.build();
try {
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get() //请求方式
.build();
//Request封装成Call对象
Call call = okHttpClient.newCall(request);
Response response = call.execute();
Log.e("result: ", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
2)异步请求
//异步请求
private void sendAsyRequest() {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.readTimeout(5, TimeUnit.SECONDS)//设置超时...
.build();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get() //请求方式
.build();
//Request封装成Call对象
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("result: ", response.body().string());
}
});
}
除了执行方式为execute与enqueue的区别,execute方式会阻塞当前线程,而enqueue方式会自动开启一个工作线程去处理事务,而且onFailure与onResponse回调都是在工作线程中触发的。
3)提交string
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "content";
Request request = new Request.Builder()
.url("request url")
.post(RequestBody.create(mediaType, requestBody))
.build();
4)提交流
RequestBody requestBody = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return MediaType.parse("text/x-markdown; charset=utf-8");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("request content");
}
};
Request request = new Request.Builder()
.url("request url")
.post(requestBody)
.build();
5)提交文件
OkHttpClient okHttpClient = new OkHttpClient();
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
File file = new File("test.md");
Request request = new Request.Builder()
.url("request url")
.post(RequestBody.create(mediaType, file))
.build();
6)提交表单
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("des", "content")
.build();
Request request = new Request.Builder()
.url("request url")
.post(requestBody)
.build();
7)提交分块请求
OkHttpClient client = new OkHttpClient();
MultipartBody body = new MultipartBody.Builder(" ")
.setType(MultipartBody.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "content"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MediaType.parse("image/png"), new File(" ")))
.build();
Request request = new Request.Builder()
.url("request url")
.post(body)
.build();
8)非系统拦截器
这里是一个简单的拦截器,用来打印出去的请求和收到的响应。
class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
应用拦截器:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
或者自定义级别:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.e("日志拦截器: ", "网络接口数据");
}
});
loggingInterceptor.setLevel(level);
builder.addInterceptor(loggingInterceptor);
okHttpClient = builder.build();
网络拦截器:
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor())
.build();
2.解析执行流程
1)OkHttpClient创建
Builder()中的分发器Dispatcher:分发事务,决定异步事务是直接处理还是缓存等待。
ConnectionPool:存储请求链接的池,比如请求链接相同,可决定复用等等操作。
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;
}
2)Request创建
Builder()中,指定请求一些参数和请求头信息
public Builder() {
this.method = "GET"; //默认get
this.headers = new Headers.Builder(); //请求头信息
}
build方法,实例化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;
}
3)Call创建
Call官方解释:为了执行请求调用Call,Call可以取消。Call对象表示单个请求/响应对(流),不能执行两次。
先看okHttpClient.newCall(request)中newCall:
//准备在将来某个时候执行
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
RealCall为Call的实现类,看看newRealCall函数:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// 安全地将调用实例发布到EventListener。
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
newRealCall中,实例化RealCall,并设置监听。看看RealCall构造:
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
可以看到之前创建好的OkHttpClient和Request都被传入,同时实例化了RetryAndFollowUpInterceptor(重定向拦截器)。
4)execute执行
public interface Call extends Cloneable {
...
Response execute() throws IOException;
...
}
execute()是Call接口中的,具体看它实现类RealCall中的操作:
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
//execute只能被执行一次,执行一次后修改标记为true,再次execute抛异常
executed = true;
}
captureCallStackTrace();//捕捉异常信息
eventListener.callStart(this);//callstart回调执行
try {
client.dispatcher().executed(this);//分发事务
Response result = getResponseWithInterceptorChain();//拦截器
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);//callfail回调执行
throw e;
} finally {
client.dispatcher().finished(this); //处理完成后调用
}
}
上面有句重点:
client.dispatcher().executed(this);
而dispatcher()只是拿到分发器:
public Dispatcher dispatcher() {
return dispatcher;
}
而executed():
public final class Dispatcher {
//同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
......
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
}
将同步请求的Call添加到队列runningSyncCalls中。可以看出分发器在execute()过程中起到了很核心的作用,最后看到execute()末尾的client.dispatcher().finished(this),这finished(this):
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(); //传入promoteCalls==false,不走这个
runningCallsCount = runningCallsCount();//获取总数
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {//同步队列无任务且回调非空
idleCallback.run();
}
}
//获取同步和异步执行队列任务总和
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
作用为将Call从同步执行队列移除。
总结:将Call的事件,通过分发器分发到到队列runningSyncCalls中,事件执行完,再通过分发器将这个事件移除。
5)enqueue执行
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
//call只被执行一次
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
重点enqueue函数:
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
//处理请求的线程池
private @Nullable ExecutorService executorService;
//存储不满足立刻运行条件的异步请求
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//存储可立刻运行的异步请求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
synchronized void enqueue(AsyncCall call) {
//当前执行的异步队列数量小于最大请求数 且 当前主机执行请求数小于主机请求数最大值
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call); //加入可立刻执行的异步请求队列
executorService().execute(call); //线程池执行单次事务
} else {
readyAsyncCalls.add(call); //不满足条件,加入缓存异步队列readyAsyncCalls
}
}
...}
看看enqueue函数的入参AsyncCall:
final class AsyncCall extends NamedRunnable {
......
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
}
是将CallBack(单次事件处理的完成的回调)赋值给AsyncCall中的Callback。那NamedRunnable是什么:
public abstract class NamedRunnable implements Runnable {
protected final String name;
protected abstract void execute();
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);
}
}
}
得知单次请求事务的处理,还是交给实现类的execute()方法去处理,即AsyncCall类,看看AsyncCall类的execute()方法:
@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) {
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);//从队列移除本次请求
}
}
下面看看移除的过程:
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//调用3参数的finish()
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();
}
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
promoteCalls函数具体如下:
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // 当前为最大请求数量
if (readyAsyncCalls.isEmpty()) return; //就绪队列为空
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);//将就绪队列的请求拿出
executorService().execute(call);//拿出后给线程池处理
}
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
可以看出:异步运行队列的请求执行完,会通过promoteCalls函数,将异步就绪队列runningAsyncCalls中满足条件的请求拿出给线程池处理
总结为:将CallBack,也就是单次事务执行完回调绑定到Runnable,也就是AsyncCall,再将AsyncCall所代表的Runnable给线程池处理,最终通过回调返回结果。