Android 4.4以上使用HttpURLConnection底层使用OkHttp实现的源码分析
Posted 火山石
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 4.4以上使用HttpURLConnection底层使用OkHttp实现的源码分析相关的知识,希望对你有一定的参考价值。
研究了一下HttpURLConnection的源码:
在使用的时候都是通过URL.openConnection()来获取HttpURLConnection对象,然后调用其connect方法进行链接,所以先从URL.penConnection()入手:
/**
* Returns a new connection to the resource referred to by this URL.
*
* @throws IOException if an error occurs while opening the connection.
*/
public URLConnection openConnection() throws IOException {
return streamHandler.openConnection(this);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
接下来就要看一下streamHandler究竟是何方神圣?我们搜一下他的赋值,实在setupStreamHandler方法中进行的:
/**
* Sets the receiver‘s stream handler to one which is appropriate for its
* protocol.
*
* <p>Note that this will overwrite any existing stream handler with the new
* one. Senders must check if the streamHandler is null before calling the
* method if they do not want this behavior (a speed optimization).
*
* @throws MalformedURLException if no reasonable handler is available.
*/
void setupStreamHandler() {
// Check for a cached (previously looked up) handler for
// the requested protocol.
streamHandler = streamHandlers.get(protocol);
if (streamHandler != null) {
return;
}
// If there is a stream handler factory, then attempt to
// use it to create the handler.
if (streamHandlerFactory != null) {
streamHandler = streamHandlerFactory.createURLStreamHandler(protocol);
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
return;
}
}
// Check if there is a list of packages which can provide handlers.
// If so, then walk this list looking for an applicable one.
String packageList = System.getProperty("java.protocol.handler.pkgs");
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (packageList != null && contextClassLoader != null) {
for (String packageName : packageList.split("\\|")) {
String className = packageName + "." + protocol + ".Handler";
try {
Class<?> c = contextClassLoader.loadClass(className);
streamHandler = (URLStreamHandler) c.newInstance();
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
}
return;
} catch (IllegalAccessException ignored) {
} catch (InstantiationException ignored) {
} catch (ClassNotFoundException ignored) {
}
}
}
// Fall back to a built-in stream handler if the user didn‘t supply one
if (protocol.equals("file")) {
streamHandler = new FileHandler();
} else if (protocol.equals("ftp")) {
streamHandler = new FtpHandler();
} else if (protocol.equals("http")) {
// 判断一下如果是HTTP协议,就会创建HtppHandler。看到这里明白了,原来使用的是okhttp.
try {
String name = "com.android.okhttp.HttpHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("https")) {
try {
String name = "com.android.okhttp.HttpsHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("jar")) {
streamHandler = new JarHandler();
}
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
这里我们就以HTTP协议为例说一下所以找到okhttp HttpHandler.openConnection()方法:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.okhttp;
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
public final class HttpHandler extends URLStreamHandler {
@Override protected URLConnection openConnection(URL url) throws IOException {
// 调用了OKHttpClient()的方法
return new OkHttpClient().open(url);
}
@Override protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
if (url == null || proxy == null) {
throw new IllegalArgumentException("url == null || proxy == null");
}
return new OkHttpClient().setProxy(proxy).open(url);
}
@Override protected int getDefaultPort() {
return 80;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
接下来就悲剧了,因为我找不到OkHttpClient()类中有open方法。
仔细查看了文档后发现在OKHttp1.6.0的时候该方法就已经已经过时了。
@Deprecated
public HttpURLConnection open(URL url)
Deprecated. moved to OkUrlFactory.open.
- 1
- 2
- 3
那我们怎么往下分析呢?很显然Android sdk中使用的OkHttp不是最新版。所以我们可以使用1.5.0版本的OKHttp接着分析。
在项目build.gradle中进行配置 compile ‘com.squareup.okhttp:okhttp:1.5.0’ 然后开始愉快的查看源码。
package com.squareup.okhttp;
import com.squareup.okhttp.internal.Util;
import com.squareup.okhttp.internal.http.HttpAuthenticator;
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
import com.squareup.okhttp.internal.http.ResponseCacheAdapter;
import com.squareup.okhttp.internal.okio.ByteString;
import com.squareup.okhttp.internal.tls.OkHostnameVerifier;
import java.io.IOException;
import java.net.CookieHandler;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.ResponseCache;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
/** Configures and creates HTTP connections. */
public final class OkHttpClient implements URLStreamHandlerFactory, Cloneable {
private final RouteDatabase routeDatabase;
private Proxy proxy;
private List<Protocol> protocols;
private ProxySelector proxySelector;
private CookieHandler cookieHandler;
private OkResponseCache responseCache;
private SSLSocketFactory sslSocketFactory;
private HostnameVerifier hostnameVerifier;
private OkAuthenticator authenticator;
private ConnectionPool connectionPool;
private boolean followProtocolRedirects = true;
private int connectTimeout;
private int readTimeout;
public OkHttpClient() {
routeDatabase = new RouteDatabase();
}
/**
* Sets the default connect timeout for new connections. A value of 0 means no timeout.
*
* @see URLConnection#setConnectTimeout(int)
*/
public void setConnectTimeout(long timeout, TimeUnit unit) {
if (timeout < 0) {
throw new IllegalArgumentException("timeout < 0");
}
if (unit == null) {
throw new IllegalArgumentException("unit == null");
}
long millis = unit.toMillis(timeout);
if (millis > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Timeout too large.");
}
connectTimeout = (int) millis;
}
/** Default connect timeout (in milliseconds). */
public int getConnectTimeout() {
return connectTimeout;
}
/**
* Sets the default read timeout for new connections. A value of 0 means no timeout.
*
* @see URLConnection#setReadTimeout(int)
*/
public void setReadTimeout(long timeout, TimeUnit unit) {
if (timeout < 0) {
throw new IllegalArgumentException("timeout < 0");
}
if (unit == null) {
throw new IllegalArgumentException("unit == null");
}
long millis = unit.toMillis(timeout);
if (millis > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Timeout too large.");
}
readTimeout = (int) millis;
}
/** Default read timeout (in milliseconds). */
public int getReadTimeout() {
return readTimeout;
}
/**
* Sets the HTTP proxy that will be used by connections created by this
* client. This takes precedence over {@link #setProxySelector}, which is
* only honored when this proxy is null (which it is by default). To disable
* proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}.
*/
public OkHttpClient setProxy(Proxy proxy) {
this.proxy = proxy;
return this;
}
public Proxy getProxy() {
return proxy;
}
/**
* Sets the proxy selection policy to be used if no {@link #setProxy proxy}
* is specified explicitly. The proxy selector may return multiple proxies;
* in that case they will be tried in sequence until a successful connection
* is established.
*
* <p>If unset, the {@link ProxySelector#getDefault() system-wide default}
* proxy selector will be used.
*/
public OkHttpClient setProxySelector(ProxySelector proxySelector) {
this.proxySelector = proxySelector;
return this;
}
public ProxySelector getProxySelector() {
return proxySelector;
}
/**
* Sets the cookie handler to be used to read outgoing cookies and write
* incoming cookies.
*
* <p>If unset, the {@link CookieHandler#getDefault() system-wide default}
* cookie handler will be used.
*/
public OkHttpClient setCookieHandler(CookieHandler cookieHandler) {
this.cookieHandler = cookieHandler;
return this;
}
public CookieHandler getCookieHandler() {
return cookieHandler;
}
/**
* Sets the response cache to be used to read and write cached responses.
*/
public OkHttpClient setResponseCache(ResponseCache responseCache) {
return setOkResponseCache(toOkResponseCache(responseCache));
}
public ResponseCache getResponseCache() {
return responseCache instanceof ResponseCacheAdapter
? ((ResponseCacheAdapter) responseCache).getDelegate()
: null;
}
public OkHttpClient setOkResponseCache(OkResponseCache responseCache) {
this.responseCache = responseCache;
return this;
}
public OkResponseCache getOkResponseCache() {
return responseCache;
}
/**
* Sets the socket factory used to secure HTTPS connections.
*
* <p>If unset, a lazily created SSL socket factory will be used.
*/
public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
this.sslSocketFactory = sslSocketFactory;
return this;
}
public SSLSocketFactory getSslSocketFactory() {
return sslSocketFactory;
}
/**
* Sets the verifier used to confirm that response certificates apply to
* requested hostnames for HTTPS connections.
*
* <p>If unset, the
* {@link javax.net.ssl.HttpsURLConnection#getDefaultHostnameVerifier()
* system-wide default} hostname verifier will be used.
*/
public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
public HostnameVerifier getHostnameVerifier() {
return hostnameVerifier;
}
/**
* Sets the authenticator used to respond to challenges from the remote web
* server or proxy server.
*
* <p>If unset, the {@link java.net.Authenticator#setDefault system-wide default}
* authenticator will be used.
*/
public OkHttpClient setAuthenticator(OkAuthenticator authenticator) {
this.authenticator = authenticator;
return this;
}
public OkAuthenticator getAuthenticator() {
return authenticator;
}
/**
* Sets the connection pool used to recycle HTTP and HTTPS connections.
*
* <p>If unset, the {@link ConnectionPool#getDefault() system-wide
* default} connection pool will be used.
*/
public OkHttpClient setConnectionPool(ConnectionPool connectionPool) {
this.connectionPool = connectionPool;
return this;
}
public ConnectionPool getConnectionPool() {
return connectionPool;
}
/**
* Configure this client to follow redirects from HTTPS to HTTP and from HTTP
* to HTTPS.
*
* <p>If unset, protocol redirects will be followed. This is different than
* the built-in {@code HttpURLConnection}‘s default.
*/
public OkHttpClient setFollowProtocolRedirects(boolean followProtocolRedirects) {
this.followProtocolRedirects = followProtocolRedirects;
return this;
}
public boolean getFollowProtocolRedirects() {
return followProtocolRedirects;
}
public RouteDatabase getRoutesDatabase() {
return routeDatabase;
}
/**
* @deprecated OkHttp 1.5 enforces an enumeration of {@link Protocol protocols}
* that can be selected. Please switch to {@link #setProtocols(java.util.List)}.
*/
@Deprecated
public OkHttpClient setTransports(List<String> transports) {
List<Protocol> protocols = new ArrayList<Protocol>(transports.size());
for (int i = 0, size = transports.size(); i < size; i++) {
try {
Protocol protocol = Util.getProtocol(ByteString.encodeUtf8(transports.get(i)));
protocols.add(protocol);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
return setProtocols(protocols);
}
/**
* Configure the protocols used by this client to communicate with remote
* servers. By default this client will prefer the most efficient transport
* available, falling back to more ubiquitous protocols. Applications should
* only call this method to avoid specific compatibility problems, such as web
* servers that behave incorrectly when SPDY is enabled.
*
* <p>The following protocols are currently supported:
* <ul>
* <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
* <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">spdy/3.1</a>
* <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-09">HTTP-draft-09/2.0</a>
* </ul>
*
* <p><strong>This is an evolving set.</strong> Future releases may drop
* support for transitional protocols (like spdy/3.1), in favor of their
* successors (spdy/4 or http/2.0). The http/1.1 transport will never be
* dropped.
*
* <p>If multiple protocols are specified, <a
* href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> will
* be used to negotiate a transport. Future releases may use another mechanism
* (such as <a href="http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02">ALPN</a>)
* to negotiate a transport.
*
* @param protocols the protocols to use, in order of preference. The list
* must contain "http/1.1". It must not contain null.
*/
public OkHttpClient setProtocols(List<Protocol> protocols) {
protocols = Util.immutableList(protocols);
if (!protocols.contains(Protocol.HTTP_11)) {
throw new IllegalArgumentException("protocols doesn‘t contain http/1.1: " + protocols);
}
if (protocols.contains(null)) {
throw new IllegalArgumentException("protocols must not contain null");
}
this.protocols = Util.immutableList(protocols);
return this;
}
/**
* @deprecated OkHttp 1.5 enforces an enumeration of {@link Protocol
* protocols} that can be selected. Please switch to {@link
* #getProtocols()}.
*/
@Deprecated
public List<以上是关于Android 4.4以上使用HttpURLConnection底层使用OkHttp实现的源码分析的主要内容,如果未能解决你的问题,请参考以下文章
如何检查我是否在Android 4.4及以上版本中以编程方式打开gps? [重复]
GetPathFromUri4kitkatAndroid 4.4 kitkat以上及以下根据uri获取路径的方法