本文共 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);  }  private         void 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/