内容简介:Android 开发只需添加依赖,如下:官方示例1:获取一个 url 上的内容并输出
Android 开发只需添加依赖,如下:
implementation("com.squareup.okhttp3:okhttp:3.13.1")
官方示例1:获取一个 url 上的内容并输出
//Http 客户端 OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { //构造请求 Request request = new Request.Builder() .url(url) .build(); //执行请求,获取数据 try (Response response = client.newCall(request).execute()) { return response.body().string(); } } 复制代码
官方示例2:给服务器 post
数据
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); } } 复制代码
简单分析一下这段代码:这个 post
请求操作看起来很简单。但是我们需要学习其中几个很重要的接口:
OKHttpClient:它代表着 http 客户端
Request:它封装了请求对象,可以构造一个 http 请求对象
Response:封装了响应结果
Call:client.newCall()调用后生成一个请求执行对象Call,它封装了请求执行过程。
下面我们结合这个例子来分析源码:
newCall().execute()
跟踪源码后发现这个方法是在 Call 中的接口,代码如下:
/** * A call is a request that has been prepared for execution. A call can be canceled. As this object * represents a single request/response pair (stream), it cannot be executed twice. */ public interface Call extends Cloneable { //省略部分代码 //同步执行请求 Response execute() throws IOException; //请求加入队列 void enqueue(Callback responseCallback); //省略部分代码 } 复制代码
Call 的实现类是 RealCall,继续追踪源码的 RealCall.java 文件,可以看到 execute 方法:
@Override public Response execute() throws IOException { //同步锁检查该请求是否已经执行,如果没有则标记executed = ture,否则抛出异常 synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); timeout.enter(); //调用了回调方法 callStart eventListener.callStart(this); try { //okhttp 客户端调用 dispatcher 将执行请求对象 client.dispatcher().executed(this); //调用了 getResponseWithInterceptorChain 方法获取到响应数据 Response,后期还会继续分析 Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { e = timeoutExit(e); //请求失败的回调 callFailed eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); //使用 dispather 对象调用 finished 方法,完成请求 } } 复制代码
接下来我们详细分析一下 dispatcher.execute 和 getResponseWithInterceptorChain 这两个方法:
跟踪源码 Dispatcher
public final class Dispatcher { //省略部分代码 /** Executes calls. Created lazily. */ private @Nullable ExecutorService executorService; /** Ready async calls in the order they'll be run. */ private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>(); /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); public Dispatcher(ExecutorService executorService) { this.executorService = executorService; } void enqueue(AsyncCall call) { synchronized (this) { readyAsyncCalls.add(call); // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to // the same host. if (!call.get().forWebSocket) { AsyncCall existingCall = findExistingCallWithHost(call.host()); if (existingCall != null) call.reuseCallsPerHostFrom(existingCall); } } promoteAndExecute(); } private <T> void finished(Deque<T> calls, T call) { Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); idleCallback = this.idleCallback; } boolean isRunning = promoteAndExecute(); if (!isRunning && idleCallback != null) { idleCallback.run(); } } } 复制代码
发现 Dispatcher 是一个调度器,它的作用是对请求进行分发。它的内部有三个队列,分别是同步请求进行队列、异步请求等待队列、异步请求执行队列。
核心方法:getResponseWithInterceptorChain
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); } 复制代码
此方法构建数个拦截器之后,又构造了一个拦截器责任链。跟踪源码 RealInterceptorChain:
RealInterceptorChain
该类主要负责将所有的拦截器串连起来,使所有的拦截器以递归的方式进行实现,从而确保只有所有的拦截器都执行完之后才会返回 Response。以下对该类中的主要方法 proceed 进行讲解:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); //用于计算拦截器调用该方法的次数 calls++; // If we already have a stream, confirm that the incoming request will use it. if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must retain the same host and port"); } // If we already have a stream, confirm that this is the only call to chain.proceed(). if (this.httpCodec != null && calls > 1) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must call proceed() exactly once"); } //生成下一个拦截器调动该方法的 RealInterceptorChain 对象,其中 index+1 用于获取下一个拦截器 RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); //获取当前拦截器 Interceptor interceptor = interceptors.get(index); //调用该拦截器并获取返回结果 Response response = interceptor.intercept(next); // Confirm that the next interceptor made its required call to chain.proceed(). if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) { throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once"); } // Confirm that the intercepted response isn't null. if (response == null) { throw new NullPointerException("interceptor " + interceptor + " returned null"); } return response; } 复制代码
总结
以上就是我们对 OkHttp 核心源码的分析。当我们发起一个请求的时候会初始化一个 Call 的实例,然后根据同步和异步的不同,分别调用它的 execute() 和 enqueue() 方法。大致过程都是通过拦截器组成的责任链,依次经过重试、桥接、缓存、连接和访问服务器等过程,来获取到一个响应并交给用户。
以上所述就是小编给大家介绍的《OkHttp 开源库使用与源码解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 优秀开源库SDWebImage源码浅析
- 优秀开源库SDWebImage源码浅析
- Californium开源框架之源码分析(三)
- Californium开源框架之源码分析(四)
- Android开源框架源码分析:Okhttp
- Android开源框架源码分析:Okhttp
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
互联网的误读
詹姆斯•柯兰(James Curran)、娜塔莉•芬顿(Natalie Fenton)、德 斯•弗里德曼(Des Freedman) / 何道宽 / 中国人民大学出版社 / 2014-7-1 / 45.00
互联网的发展蔚为壮观。如今,全球的互联网用户达到20亿之众,约占世界人口的30%。这无疑是一个新的现象,对于当代各国的经济、政治和社会生活意义重大。有关互联网的大量大众读物和学术著作鼓吹其潜力将从根本上被重新认识,这在20世纪90年代中期一片唱好时表现尤甚,那时许多论者都对互联网敬畏三分,惊叹有加。虽然敬畏和惊叹可能已成过去,然而它背后的技术中心主义——相信技术决定结果——却阴魂不散,与之伴生的则......一起来看看 《互联网的误读》 这本书的介绍吧!