使用
同步
String url = "https://wanandroid.com/wxarticle/chapters/json";
OkHttpClient okHttpClient = new OkHttpClient();
Request request= new Request.Builder().url(url).build();
Response response = okHttpClient.newCall(request).execute();
異步
String url ="https://wanandroid.com/wxarticle/chapters/json";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
}
});
還可以添加自定義攔截器、設置超時時間、請求過程事件監聽、dns、緩存等等。。。
添加攔截器 和 事件監聽的例子 更詳細的功能使用看官方網站
OkHttpClient client = new OkHttpClient.Builder().eventListener(new EventListener() {
@Override
public void callStart(okhttp3.Call call) {
super.callStart(call);
System.out.println("callStart");
}
@Override
public void dnsStart(okhttp3.Call call, String domainName) {
super.dnsStart(call, domainName);
System.out.println("dnsStart");
}
@Override
public void dnsEnd(okhttp3.Call call, String domainName, List<InetAddress> inetAddressList) {
super.dnsEnd(call, domainName, inetAddressList);
System.out.println("dnsEnd");
}
}).addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
System.out.println("我先做點事情");
return chain.proceed(chain.request());
}
}).build();
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
源碼分析 (主流程)
OkHttpClient 和 Request 通過建造者模式構建,主要是基礎屬性 攔截器、url、dns等等
同步請求源碼流程
發起真正執行請求
Response response = client.newCall(request).execute();
最終是通過RealCall 去執行execute()
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
ReclCall裏則是通過dispatcher 調度器去執行,同步請求時將call存入
runningSyncCalls 然後發起請求 通過責任鏈模式 返回結果後從隊列中移除call,最終返回結果
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
//加到同步隊列中
client.dispatcher().executed(this);
//獲取結果返回
return getResponseWithInterceptorChain();
} finally {
//從同步隊列中移除
client.dispatcher().finished(this);
}
}
// client.dispatcher().executed(this)
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
異步請求源碼流程
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
異步請求有兩個隊列 readyAsyncCalls和runningAsyncCalls
1、先是加入到readyAsyncCalls 隊列 預備隊列
2、從readyAsyncCalls和runningAsyncCalls 中找出和此次host相同的請求,如果存在記錄個數
3、繼續執行
void enqueue(AsyncCall call) {
synchronized (this) {
//加入readyAsyncCalls隊列
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
//RealCall的forWebSocket=false
if (!call.get().forWebSocket) {
//從readyAsyncCalls和runningAsyncCalls 找出host相同的請求
AsyncCall existingCall = findExistingCallWithHost(call.host());
//如果找到相同的 則將host計數賦值
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
//推動執行
promoteAndExecute();
}
//找出相同的host
@Nullable private AsyncCall findExistingCallWithHost(String host) {
for (AsyncCall existingCall : runningAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
for (AsyncCall existingCall : readyAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
return null;
}
接下來執行promoteAndExecute(),這裏涉及一個邏輯 ,如何將readyAsyncCalls裏的call轉移到runningAsyncCalls中
規則是:如果runningAsyncCalls大於等於64 默認 或者正在執行的host 相同的已經超過5個默認 則不轉移 每次取出要執行的call都是這樣去判斷的
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();
//如果runningAsyncCalls大於等於maxRequests 默認64 則直接中斷
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//或者 如果相同host大於等於maxRequestsPerHost 默認5 也不添加
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
//從readyAsyncCalls中移除
i.remove();
//將host的次數++
asyncCall.callsPerHost().incrementAndGet();
//加入到可執行的executableCalls隊列中 臨時隊列
executableCalls.add(asyncCall);
//加到runningAsyncCalls中
runningAsyncCalls.add(asyncCall);
}
//是否正常執行 runningAsyncCalls.size() + runningSyncCalls.size() 同步隊列或異步隊列有數據則證明有在運行 因爲運行結束會移除
isRunning = runningCallsCount() > 0;
}
//將滿足條件的可執行的call 執行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//調用executeOn 其實是一個Runnable
asyncCall.executeOn(executorService());
}
return isRunning;
}
//AsyncCall 繼承NamedRunnable 包裝了一下
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();
}
在AsyncCall中執行executeOn方法
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
//線程池 執行runnable 即 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); // This call is no longer running!
}
}
}
@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 {
//從runningAsyncCalls移除請求call 並且在相同的host上減1
client.dispatcher().finished(this);
}
}
}
除了五大攔截器 主線流程大致如此
五大攔截器大致邏輯(圖片來自享學)
備註下連接池 (圖片來自享學)
核心線程數:0,不會緩存線程,所有線程60秒內沒工作就會被回收
最大線程數爲:Integer.MAX_VALUE
等待隊列:SynchronousQueue,兩者結合達最大吞吐量,沒有空閒線程無需等待,直接創建新的執行
//連接池的線程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
清理任務的線程池
private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));