本文共 6031 字,大约阅读时间需要 20 分钟。
目录
compile 'com.squareup.okhttp3:okhttp:3.9.0' //okttp依赖
Okhttp同步需要注意:发送请求后,就会进入阻塞状态,直到收到响应。
OkHttpClient mClient = new OkHttpClient.Builder().build(); Request request = new Request.Builder().url("http://www.baidu.com").get().build(); //可以把call看做连接Request和Response的桥梁 Call call = mClient.newCall(request); try { Response response = call.execute(); LogUtils.json(response.body().string()); } catch (IOException e) { e.printStackTrace(); }
注意:onResponse()和onFailure()两个回调方法是在工作线程即子线程进行的
OkHttpClient mClient = new OkHttpClient.Builder().build(); Request request = new Request.Builder().url("http://www.baidu.com").get().build(); //可以把call看做连接Request和Response的桥梁 Call call = mClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { LogUtils.json(response.body().string()); runOnUiThread(new Runnable() { @Override public void run() { tvShow.setText("eeeeee"); } }); } });
下面我们来一步步分析,首先,就是
OkHttpClient mClient = new OkHttpClient.Builder().build();
我们来查看OkHttpClient的内部Builder类的构造方法:
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; }
初始化了一堆东西,比较重要的就是Dispatcher、ConnectionPool的初始化。Dispatcher和异步请求有关,我们先不讲,我们重要讲一下ConnectionPool。
ConnectionPool,顾名思义,就是连接池的意思,我们可以把客户端与服务端的链接抽象为一个个Connection,而每一个Connection都会被放在ConnectionPool中统一管理。
ConnectionPool有两个作用:
Request request = new Request.Builder().url("http://www.baidu.com").get().build();
可以看出,这也是一个build构造模式,先看内部类Builder
Builder(Request request) { this.url = request.url; this.method = request.method; this.body = request.body; this.tag = request.tag; this.headers = request.headers.newBuilder(); }
通过Builder来设置请求地址url、请求方法method、头部信息headers等信息。
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; }
然后再把Builder的这些参数传递给Request
Call是一个接口类,具体实现是在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; }
再接着往下看:
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); }
RetryAndFollowUpInterceptor是重定向拦截器
我们来看RealCall的execute方法
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); } }
核心代码是这些:
client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result;
需要着重介绍的就是这个方法:
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
runningSyncCalls是一个存放RealCall的队列,Deque继承自Queue
private final DequerunningSyncCalls = new ArrayDeque<>();
由此,我们可以看到同步的请求会被放到一个队列之中。在这里先简单讲解一下Dispatcher
可以看到,Dispatcher的主要作用就是保存Call请求的各种状态,然后它又维护了一个线程池,用于执行网络请求。具体就是,这些call被一个个地发送给一个个的子线程来执行(异步请求,不是同步请求)。
回到execute()方法:
finally { client.dispatcher().finished(this); }
点进去:
void finished(RealCall call) { finished(runningSyncCalls, call, false); } privatevoid finished(Deque 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(); } }
需要注意两点:第一,需要执行calls.remove(call)这个操作,如果未执行,会抛出异常;
第二,同步请求不会走promoteCalls()这个方法,异步请求才会走,我们在上面关于Dispatcher的图中可以看到这个方法。
转载地址:http://puttz.baihongyu.com/