Okhttp是什么
Okhttp是Java上很流行的一款网络情况框架,由square出品
基本使用
String url = "http://co-api.51wnl.com//Calendar/GetStar?starName=aries&client=ceshi&token=7AFA7AC511153E696C09D04F94816CB1";
Request request = new Builder().url(url).build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String string = response.body().string();
Log.e("OkhttpActivity", "onResponse: " + string);
}
});
这是Okhttp最基本的使用方式,从上述代码就可以看出OkHttp是使用是先需要创建一个Request对象然后通过client执行这个请求,我这里是使用异步的方式Okhttp自动切换到子线程进行网络请求,因为在Android中主线程是不能进行网路请求的
Request
翻译过来就是请求的意思,Request主题为以下是个部分
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
- url这个是网路请求的地址自然是不能少的
- method使用的请求方式,上述我们使用的是Builder模式创建的Request对象,则使用的是默认的请求方式GET
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
这个是Request.Builder的构造函数这里默认给method赋值了GET,所以如果我们使用Builder模式创建Request对象就默认使用的GET方式发送网路请求
- headers是Request的请求头部
- body是我们的请求体部分
Okhttp很强大那自然是支持restful api的我们看下都是哪些函数
public Builder get() {
return method("GET", null);
}
public Builder head() {
return method("HEAD", null);
}
public Builder post(RequestBody body) {
return method("POST", body);
}
public Builder delete(@Nullable RequestBody body) {
return method("DELETE", body);
}
public Builder delete() {
return delete(Util.EMPTY_REQUEST);
}
public Builder put(RequestBody body) {
return method("PUT", body);
}
public Builder patch(RequestBody body) {
return method("PATCH", body);
}
我们只要调用对应的函数就可以使用Okhttp发送出对应action的网路请求.
OkhttpClient
当我们调用enqueue()函数时会自动给我使用线程池执行这个网路请求,实际执行enqueue()函数的是RealCall这个类接下来我们看下它的源码
@Override 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));
}
在最后一行okhttpClient使用调度器创建了一个异步的call
client.dispatcher().enqueue(new AsyncCall(responseCallback));
接下来我们看下这个调度器
Dispatcher
我们前面调用的enqueue()其实最终是调用到了这个类这里
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
//判断正在执行的请求有多少个,maxReuests = 64
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//判断和当前同一个host的请求有多少个 maxRequestsPerHost = 5
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
在这里拿到了所有可以执行的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;
}
在这里拿到了取得了一个线程池,asyncCall.executeOn(executorService());我们在之前那个函数的名称(大概翻译过来的意思就是 将这个call在这个线程池中执行)
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
这里就是把可执行的请求放到了线程池中执行,我们直接看到RealCall#run方法
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();
}
realCall继承自NamedRunnable 而NamedRunnable最终执行到了execute中
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
e = timeoutExit(e);
if (signalledCallback) {
// Do not signal the callback twice!
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);
}
}
}
Response response = getResponseWithInterceptorChain();这里开始调用拦截器了,从这里开始才是okhttp的重头戏
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);
}
okhttp内置了5个拦截器
- RetryAndFollowUpInterceptor 重试拦截器
- BridgeInterceptor 桥接拦截器
- CacheInterceptor 缓存拦截器
- ConnectInterceptor 链接拦截器
- CallServerInterceptor 读写拦截器
我们继续往下看okhttp是如何通过他们获取到了网络请求返回
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
}
通过上面的方法开始调用到了我们第一个拦截器
RetryAndFollowUpInterceptor#intercept
注意
库引入
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
如果是Android P系统因为默认是禁用http明文请求的方式我们需要在xml中配置开启明文请求
首先在res文件夹下创建名为xml的文件夹,再在xml文件夹下创建network_security_config.xml文件内容如下
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
之后在AndroidManifest.xml的application标签下加入如下配置即可
android:networkSecurityConfig="@xml/network_security_config"
还有别忘记打开网路权限,INTERNET只要声明不需要动态申请
<uses-permission android:name="android.permission.INTERNET" />