目录
前言
接上文网络请求框架OkHttp的同步异步简单使用介绍《》,今天就对同步请求的源码分析一下,加深一下印象。记录一下,方便自己查阅。
正文
这里用的框架版本
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
有新版本,我没有升级,暂时就以这个记录。
下面是同步代码
//创建OkHttpClient OkHttpClient client = new OkHttpClient.Builder().build(); //创建Request Request request = new Request.Builder().get().url("https://www.91es.com/").build(); //创建Call,其实也是对request的封装 Call call = client.newCall(request); //同步请求 Response response = call.execute();
OkHttpClient
OkHttpClient的创建是用了Builder模式。进入Builder()
Builder()
public Builder() { dispatcher = new Dispatcher(); protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; eventListenerFactory = EventListener.factory(EventListener.NONE); proxySelector = ProxySelector.getDefault(); if (proxySelector == null) { proxySelector = new NullProxySelector(); } 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; callTimeout = 0; connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; pingInterval = 0; }
也就是参数的初始化
Request
也是用了Builder模式,初始化请求方式和添加url。
Builder()
public Builder() { this.method = "GET"; this.headers = new Headers.Builder(); }
请求方式可以用默认的,也可以进行修改。
public Builder get() { return method("GET", null); } public Builder post(RequestBody body) { return method("POST", body); } public Builder delete(@Nullable RequestBody body) { return method("DELETE", body); } public Builder put(RequestBody body) { return method("PUT", body); } public Builder patch(RequestBody body) { return method("PATCH", body); }
url()
传入请求url
public Builder url(String url) { if (url == null) throw new NullPointerException("url == null"); if (url.regionMatches(true, 0, "ws:", 0, 3)) { url = "http:" + url.substring(3); } else if (url.regionMatches(true, 0, "wss:", 0, 4)) { url = "https:" + url.substring(4); } return url(HttpUrl.get(url)); }
进行null判断和一定规则转换
public Builder url(HttpUrl url) { if (url == null) throw new NullPointerException("url == null"); this.url = url; return this; }
最终传入到Request的url中。
Call
# OkHttpClient.java @Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false); }
真正调用的是RealCall的newRealCall()
newRealCall()
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { //创建RealCall RealCall call = new RealCall(client, originalRequest, forWebSocket); //初始化eventListener call.eventListener = client.eventListenerFactory().create(call); return call; }
这里创建了RealCall对象
RealCall
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); this.timeout = new AsyncTimeout() { @Override protected void timedOut() { cancel(); } }; this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS); }
execute()
同步请求。Call中没有实现,在RealCall中实现了,而且上面创建并返回的就是RealCall对象。
# RealCall.java @Override public Response execute() throws IOException { synchronized (this) { //是否执行过标志,如果已经请求过,就不能再次请求了 if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); timeout.enter(); eventListener.callStart(this); try { //同步请求 client.dispatcher().executed(this); //获取Response Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { e = timeoutExit(e); eventListener.callFailed(this, e); throw e; } finally { //通知请求结束 client.dispatcher().finished(this); } }
上面有备注,我们看重点
client.dispatcher().executed(this);
executed()
调用的是Dispatcher的,很简单,也就是添加到同步任务列表中。
synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
getResponseWithInterceptorChain()
拦截链创建,这次才是真正的网络请求。
Response getResponseWithInterceptorChain() throws IOException { // 创建需要的拦截器,并添加到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)); //创建RealInterceptorChain拦截器链 //也就是把上面拦截器进行链接在一起,一级一级的调用,返回Response Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); return chain.proceed(originalRequest); }
下面是主要的拦截器
RetryAndFollowUpInterceptor BridgeInterceptor CacheInterceptor ConnectInterceptor CallServerInterceptor
进入proceed,这里是会把所有的拦截器串在一起。
# RealInterceptorChain.java @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 { //略 //[重点],获取下一个拦截器链(index + 1),也就是第一个不处理 RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout); //获取list中的拦截器 Interceptor interceptor = interceptors.get(index); //[重点]调用拦截器的intercept() Response response = interceptor.intercept(next); //略 return response; }
关注
Response response = interceptor.intercept(next);
interceptor就是我们上面存在interceptors中的拦截器。第一个不处理,也就是上面访问第二个RetryAndFollowUpInterceptor。
因此上面等于
RetryAndFollowUpInterceptor.intercept(next)
这里只是简单介绍,细节不介绍哈,目前关注就是如何串在一起的。
# RetryAndFollowUpInterceptor.java @Override public Response intercept(Chain chain) throws IOException { while (true) { //略 Response response; boolean releaseConnection = true; try { //[重点]又调用了proceed(),是不是又回到上面了,index+1 //response是下一个拦截器返回的。 response = realChain.proceed(request, streamAllocation, null, null); releaseConnection = false; } catch (RouteException e) { } catch (IOException e) { } finally { } } }
proceed()中的index+1,那就是再一次执行下一个拦截器。
类似于递归,只是每次调用的拦截器不一样,直到遍历完interceptors。
finished
void finished(RealCall call) { finished(runningSyncCalls, call); }
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(); } }
参考文章
-
《
历史上的今天
暂无评论...
随机推荐
MediaPlayer源码介绍3
前言我们继续介绍MediaPlayer的源码,继《MediaPlayer源码介绍2》和《mediaserver的启动》后,MediaPlayer也进入了MediaPlayerService的接口调用中。今天我们继续以setDataSource为例,看看其在MediaPlayerService的...
Windows软件开机多个
前言有时候软件需要多开,只开一个操作不方便,比如Notepad++进行日志查询时,多开一个可以拖入其他更多的文件,因此想是开启多个界面。正文百度和谷歌后发现真的有人这么干,如下。找到一个Notepad++的快捷方式(桌面或启动菜单中)属性,选中"Shortcut"(快捷键) Tab,编辑 T...
Android中关于焦点的记录
前言焦点管理是Android中比较重要的一个点,这也是Android对播放器的一个约束条件,但手机上的播放器应用都不太准守这个准则,所以就就可以存在混音问题。这里记录一下我自己的理解,当然,由于文笔过于拙,内容不会分享,谢谢。正文代码片段AudioFocusManager.javapu...
MediaProvider源码分析
前言MediaProvider继承自ContentProvider,是Android用于存储图片、音频、视频和文档等多媒体信息,提供给其他需要的应用使用。今天就对MediaProvider应用代码进行一定学习。参考网上大佬文章,记录一下过程。这里是用了Android P源码分析正文M...
史铁生:故乡的胡同
北京很大,不敢说就是我的故乡。我的故乡很小,仅北京城之一角,方圆大约二里,东和北曾经是城墙现在是二环路。其余的北京和其余的地球我都陌生。二里方圆,上百条胡同密如罗网,我在其中活到四十岁。编辑约我写写那些胡同,以为简单,答应了,之后发现这岂非是要写我的全部生命?办不到。但我的心神便又走进那些胡同,看...
[摘]Android图片加载框架之Glide和Picasso的区别
前言Glide和Picasso在实际中很常用,也容易忘记各个的优缺点。此文整理很全,因此摘抄于此,方便自己查阅。本文摘抄《Android图片加载框架之(Glide和Picasso的区别,Glide的简单使用)》)。正文Glide,一个被google所推荐的图片加载库,常见的还有Picas...