您的位置:首页 > 理论基础 > 计算机网络

OKHttp详解

2016-06-07 19:22 519 查看

OkHttp : Java和Android 高效http库,支持SPDY

http是现在主流应用使用的网络请求方式, 用来交换数据和内容, 有效的使用HTTP可以使你的APP 变的更快和减少流量的使用

OkHttp 是一个很棒HTTP客户端:

支持SPDY, 可以合并多个到同一个主机的请求

 使用连接池技术减少请求的延迟(如果SPDY是可用的话)

 使用GZIP压缩减少传输的数据量

 缓存响应避免重复的网络请求

当你的网络出现拥挤的时候,就是OKHttp 大显身手的时候, 它可以避免常见的网络问题,如果你的服务是部署在不同的IP上面的,如果第一个连接失败, OkHTtp会尝试其他的连接. 这个对现在IPv4+IPv6 中常见的把服务冗余部署在不同的数据中心上.  OkHttp 将使用现在TLS特性(SNI ALPN) 来初始化新的连接.
如果握手失败, 将切换到SLLv3使用OkHttp很容易,   同时支持 异步阻塞请求和回调.


okhttp主要有路由、连接协议、拦截器、代理、安全性认证、连接池以及网络适配,拦截器主要是指添加,移除或者转换请求或者

回应的头部信息,总流程图如下:



okhttp的使用

使用前,对于Android Studio的用户,可以选择添加:

compile 'com.squareup.okhttp:okhttp:2.4.0'
或者Eclipse的用户,可以下载最新的jar
okhttp he latest JAR ,添加依赖就可以用了。

注意:okhttp内部依赖okio,别忘了同时导入okio:

gradle:
compile 'com.squareup.okio:okio:1.5.0'


okhttp可实现以下几种功能:

一般的get请求
一般的post请求
基于Http的文件上传
文件下载
加载图片
支持请求回调,直接返回对象、对象集合
支持session的保持


httpGet:

//创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
//创建一个Request
final Request request = new Request.Builder()
.url("https://github.com/Android")
//添加头。在使用时头加不加取决于你用不用
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Accept", "application/json; q=0.5")
.addHeader("Accept", "application/vnd.github.v3+json")
.build();

//通过request的对象去构造得到一个Call对象(类似于将你的请求封装成了任务,既然是任务,就会有execute()和cancel()等方法。)
Call call = mOkHttpClient.newCall(request);
//请求加入调度

//以异步的方式去执行请求,这里是将call加入调度队列
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e){//请求失败返回对应的请求,及造成失败的异常
}

@Override
public void onResponse(final Response response) throws IOException //请求成功返回对应的响应
{
//String htmlStr =  response.body().string();
}
});//同步get和异步get的的区别是这里的call调用的是enqueue()方法-(异步)还是excute()方法-(同步)。
需要注意几点:

onResponse回调的参数是response,一般情况下,比如我们希望获得返回的字符串,可以通过
response.body().string()
获取;如果希望获得返回的二进制字节数组,则调用
response.body().bytes()
;如果你想拿到返回的inputStream,则调用
response.body().byteStream()。(有inputStream我们就可以通过IO的方式写文件。)由此我们可以看出,
onResponse方法
执行的线程并不是UI线程。

okhttp支持异步的方式去执行,也支持阻塞的方式,直接调用
call.execute()
通过返回一个
Response即为阻塞方式执行

OkHttp官方文档并不建议我们创建多个OkHttpClient,因此全局使用一个。 如果有需要,可以使用clone方法,再进行自定义。

httpPost:

Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
FormEncodingBuilder builder = new FormEncodingBuilder();
builder.add("username","pamper"); //post请求的参数,可添加多个键值对。
//构造Request对象
Request request = new Request.Builder()
.url(url)
.post(builder.build())
.build();
mOkHttpClient.newCall(request).enqueue(new Callback(){});

如果是Json数据:

public static final MediaType JSON = MediaType.parse("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();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}




基于Http的文件上传

File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");
/*构造请求体*/
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
/*构造请求体*/
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)

.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"username\""),
RequestBody.create(null, "PAMPER"))   //键值对做参数

.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"mFile\";
filename=\"wjd.mp4\""), fileBody) //文件作为传送的参数

.build();

Request request = new Request.Builder()
.url("http://192.168.1.103:8080/okHttpServer/fileUpload")
.post(requestBody)
.build();

Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback()
{
//...
});

这里其实类似于拼接模拟浏览器行为的方式,如果你对这块不了解,可以参考:http://blog.csdn.net/lmj623565791/article/details/23781773

图片下载:通过回调的Response拿到byte[]然后decode成图片

文件下载:就是拿到inputStream做写文件操作


具体实现参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html  个人这篇博文觉得写得很详细,就没有粘过来

okhttp源码解析

OkHttpClient:

源码中有一段英文介绍了他的用途:

which can be used to send HTTP requests and read their responses. Most applications can use a single OkHttpClient for all of their HTTP requests,benefiting from a shared response cache, thread pool, connection re-use, etc.

这段话的意思是 OkHttpClient是用来发送和接收请求的类,大多数应用使用一个OkHttpClient来进行HTTP请求,这得益于他共享的响应缓存,线程池、和连接复用等等。

在这个类中以下几个属性比较重要:

final Dispatcher dispatcher //分发器
final interceptors;//截获器
final List<Interceptor> List<Interceptor> networkInterceptors; //截获器=对请求进行增删改的操作
final int connectTimeout;//建立TCP连接的时候多长时间没回复
final int readTimeout;
final int writeTimeout;

主要是构造一些东西,业务逻辑较少,大部分业务逻辑由底层实现

public static final class Builder {

.......
public Builder() {
dispatcher = new Dispatcher();

......
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
//从这里我们可以看出,在无参构造器中 不管是连接还是读写,默认的时间为10秒

//你也可以使用自己定义的okHttpClient去设置相关的参数,如连接等超时的时间

Builder(OkHttpClient okHttpClient) { this.dispatcher = okHttpClient.dispatcher;
...
this.connectTimeout = okHttpClient.connectTimeout; this.readTimeout = okHttpClient.readTimeout; this.writeTimeout = okHttpClient.writeTimeout;}

//另外 okHttpClient 的静态内部类 Builder里提供了设置这些属性的方法。如:
/** * Sets the default connect timeout for new connections. A value of 0 means no timeout, * otherwise values must be between 1 and {@link Integer#MAX_VALUE} when converted to * milliseconds. */public Builder connectTimeout(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.");
if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small.");
connectTimeout = (int) millis;
return this;
}

Call:

打开Call.java首先映入眼帘的是:

/**
* 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.
*/

这句话清楚地解释了Call这个类的特点,他是已经准备执行的请求,他可以被取消。由于这个对象(Call对象)代表一个单一的请求/响应对(流),它不能被执行两次。

Call是一个接口,他拥有一个内部接口,这个接口提供两了Call的实现类对象的生成方法

interface Factory {
Call newCall(Request request);
}


另两个重要的方法如下:

/**
*  Invokes the request immediately, and blocks until the response can be processed or is in
* error.
* 立即执行请求,并且进入阻塞状态,直到上一个请求被执行完或者执行出错。
*/Response execute() throws IOException; //同步的/** * Schedules the request to be executed at some point in the future. * 计划在将来某个时候执行的请求:不马上执行,把他放在一个队列里。 */void enqueue(Callback responseCallback); //异步的

RealCall:Call的实现类。

final class RealCall implements Call {
}

//首先我们看一下execute()方法的实现:
@Override public Response execute() throws IOException {
synchronized (this) { //同步锁,线程同步。。。当出锁之后别的才可以进来。
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}

 try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);//可以有很多截获器,然后call会依次的遍历截获器,然后把
//对应的request返回回来。
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}


Dispatcher里面excute方法的实现如下:

分发器只对异步起作用,同步的不起作用。

/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
从这我们可以看出,这里并不是真的执行了excute方法,而是将RealCall的对象加入Deque


/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public interface Deque<E> extends Queue<E> {
...}
由此我们可以看出Deque是一个队列。

getResponseWithInterceptorChain:

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
/**
三个参数分别为:索引,请求,socket
*/
 Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);//应用层的截获器链条
return chain.proceed(originalRequest);//
}


@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
Interceptor interceptor = client.interceptors().get(index);//通过索引识别第几个加进来的。
//也就是通过索引区分截获器.这里虽然new了一个新的,但是他启用的上一个截获器。
Response interceptedResponse = interceptor.intercept(chain);

if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}

return interceptedResponse;//如果还有就返回对应的响应
}

// No more interceptors. Do HTTP.
return getResponse(request, forWebSocket); //说明遍历完成了。此时发送网络请求。
}
}

发送网络请求的代码如下:

/**
* Performs the request and returns the response. May return null if this call was canceled.
*/
Response getResponse(Request request, boolean forWebSocket) throws IOException {
// Copy body metadata to the appropriate request headers.
RequestBody body = request.body();//构造请求体
//---- 与HTTP协议相关-------------------------------------------//
if (body != null) {
Request.Builder requestBuilder = request.newBuilder();

MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}

long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}

request = requestBuilder.build();
}
//---- 与HTTP协议相关-------------------------------------//
 // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
//真正开始和网络打交道 HttpEngine的作用:处理网络拦截器、管理请求发送和回复
 engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);
int followUpCount = 0; while (true) {
if (canceled) {//如果请求取消了,释放 StreamAllocation 并抛出异常
engine.releaseStreamAllocation(); throw new IOException("Canceled");
}
boolean releaseConnection = true;
try {
engine.sendRequest();//发送请求
engine.readResponse(); //读取响应
releaseConnection = false;
} catch (RequestException e) {
// The attempt to interpret the request failed. Give up.
throw e.getCause();
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
HttpEngine retryEngine = engine.recover(e.getLastConnectException(), null);
if (retryEngine != null) {
releaseConnection = false;
engine = retryEngine;
  continue;
}
// Give up; recovery is not possible.
throw e.getLastConnectException();
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
HttpEngine retryEngine = engine.recover(e, null);
if (retryEngine != null) {
releaseConnection = false;
engine = retryEngine;
continue;
}
// Give up; recovery is not possible.
throw e;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
StreamAllocation streamAllocation = engine.close(); //关闭engine
//StreamAllocation的作用:申请和释放连接资源--他协调了 Connection、Streams及Call。下面简要的分析了其代码。
streamAllocation.release(); //释放资源 } }
Response response = engine.getResponse();
Request followUp = engine.followUpRequest();
if (followUp == null) {
if (!forWebSocket) {
engine.releaseStreamAllocation();
} return response;
}
StreamAllocation streamAllocation = engine.close();
if (++followUpCount > MAX_FOLLOW_UPS) { //请求数超出上线
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (!engine.sameConnection(followUp.url())) {
streamAllocation.release();
streamAllocation = null;
}
request = followUp;
engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null, response);
}
}

Request.java

public final class Request {
private final HttpUrl url;
private final String method;//  get/post/delete等等
private final Headers headers; //请求头
private final RequestBody body; //请求体
private final Object tag;

private volatile URI javaNetUri; // Lazily initialized.
private volatile CacheControl cacheControl; // Lazily initialized.

...


StreamAllocation.java

public final class StreamAllocation {
private final ConnectionPool connectionPool;

// State guarded by connectionPool.
private RouteSelector routeSelector; //线路选择器
private RealConnection connection; //连接
private HttpStream stream; //流
...


/**
* Finds a connection and returns it if it is healthy. If it is unhealthy the process is repeated
* until a healthy connection is found.
*/
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, boolean connectionRetryEnabled, boolean doExtensiveHealthChecks)
throws IOException, RouteException {
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
connectionRetryEnabled);

// If this is a brand new connection, we can skip the extensive health checks.
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}

// Otherwise do a potentially-slow check to confirm that the pooled connection is still good.
if (candidate.isHealthy(doExtensiveHealthChecks)) {
return candidate;
}

connectionFailed(new IOException());
}
}


/**
* Returns a connection to host a new stream. This prefers the existing connection if it exists,
* then the pool, finally building a new connection.
*/
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
boolean connectionRetryEnabled) throws IOException, RouteException {
Route selectedRoute;
synchronized (connectionPool) {
if (released) throw new IllegalStateException("released");
if (stream != null) throw new IllegalStateException("stream != null");
if (canceled) throw new IOException("Canceled");

RealConnection allocatedConnection = this.connection;
if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
return allocatedConnection;
}

// Attempt to get a connection from the pool.
RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
if (pooledConnection != null) {
this.connection = pooledConnection;
return pooledConnection;
}

selectedRoute = route;
}

if (selectedRoute == null) {
selectedRoute = routeSelector.next();
synchronized (connectionPool) {
route = selectedRoute;
}
}
RealConnection newConnection = new RealConnection(selectedRoute);
acquire(newConnection);

synchronized (connectionPool) {
Internal.instance.put(connectionPool, newConnection);
this.connection = newConnection;
if (canceled) throw new IOException("Canceled");
}

newConnection.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),
connectionRetryEnabled);
routeDatabase().connected(newConnection.route());

return newConnection;
}

public void streamFinished(boolean noNewStreams, HttpStream stream) {
synchronized (connectionPool) {
if (stream == null || stream != this.stream) {
throw new IllegalStateException("expected " + this.stream + " but was " + stream);
}
if (!noNewStreams) {
connection.successCount++;
}
}
deallocate(noNewStreams, false, true);
}


/**
* Releases resources held by this allocation. If sufficient resources are allocated, the
* connection will be detached or closed.
*/
private void deallocate(boolean noNewStreams, boolean released, boolean streamFinished) {
RealConnection connectionToClose = null;
synchronized (connectionPool) {
if (streamFinished) {
this.stream = null;
}
if (released) {
this.released = true;
}
if (connection != null) {
if (noNewStreams) {
connection.noNewStreams = true;
}
if (this.stream == null && (this.released || connection.noNewStreams)) {
release(connection);
if (connection.allocations.isEmpty()) {
connection.idleAtNanos = System.nanoTime();
if (Internal.instance.connectionBecameIdle(connectionPool, connection)) {
connectionToClose = connection;
}
}
connection = null;
}
}
}
if (connectionToClose != null) {
Util.closeQuietly(connectionToClose.socket());
}
}


Connection.java

The sockets and streams of an HTTP, HTTPS, or HTTPS+SPDY connection. May be used for multiple HTTP request/response
exchanges. Connections may be direct to the origin server or via a proxy.

一个HTTP、HTTPS或者Https_SPDY连接的套接字和流,
可用于多个HTTP请求/响应的交流。连接可以直接到原始服务器或通过代理
Typically instances of this class are created, connected and exercised automatically by the HTTP client.
Applications may use this class to monitor HTTP connections as members of a
{@linkplain ConnectionPool connection pool}.

通常情况下这个类的对象被创建后将会由Http 客户端自动连接和执行。应用程序可以使用这个类来监视HTTP连接为一个
“linkplain连接池连接池成员}。
public interface Connection {}
其实现类:RealConnection:

collection 的 noNewStream(鉴别这个connection能不能用,能不能进行流的读写)属性,如果为true表示:不能再加入流,他会自然而然的被连接池回收



HttpStream的作用:

一、与读写绑定

二、写与协议相关的header、body及与读协议相关的response。

HttpEngine.java

/**
* Flushes the remaining request header and body, parses the HTTP response headers and starts
* reading the HTTP response body if it exists.
*/
public void readResponse() throws IOException {
if (userResponse != null) {
return; // Already ready.
}
if (networkRequest == null && cacheResponse == null) {
throw new IllegalStateException("call sendRequest() first!");
}
if (networkRequest == null) {
return; // No network response to read.
}

Response networkResponse;

//这里有一个状态机:
 if (forWebSocket) {
httpStream.writeRequestHeaders(networkRequest);
networkResponse = readNetworkResponse();
} else if (!callerWritesRequestBody) { //callerWritesRequestBody 通常都为false

//创建网络应用层的截获器链条。
 networkResponse = new NetworkInterceptorChain(0, networkRequest).proceed(networkRequest);
} else {
// Emit the request body's buffer so that everything is in requestBodyOut.
if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {
bufferedRequestBody.emit();
}

// Emit the request headers if we haven't yet. We might have just learned the Content-Length.
if (sentRequestMillis == -1) {
if (OkHeaders.contentLength(networkRequest) == -1
&& requestBodyOut instanceof RetryableSink) {
long contentLength = ((RetryableSink) requestBodyOut).contentLength();
networkRequest = networkRequest.newBuilder()
.header("Content-Length", Long.toString(contentLength))
.build();
}

//写网络请求--写入socket。
 httpStream.writeRequestHeaders(networkRequest);
}

// Write the request body to the socket.
if (requestBodyOut != null) {
if (bufferedRequestBody != null) {
// This also closes the wrapped requestBodyOut.
bufferedRequestBody.close();
} else {
requestBodyOut.close();
}
if (requestBodyOut instanceof RetryableSink) {
httpStream.writeRequestBody((RetryableSink) requestBodyOut);
}
}

networkResponse = readNetworkResponse();
}

receiveHeaders(networkResponse.headers());

// If we have a cache response too, then we're doing a conditional get.
if (cacheResponse != null) {
if (validate(cacheResponse, networkResponse)) {
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
releaseStreamAllocation();

// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
InternalCache responseCache = Internal.instance.internalCache(client);
responseCache.trackConditionalCacheHit();
responseCache.update(cacheResponse, stripBody(userResponse));
userResponse = unzip(userResponse);
return;
} else {
closeQuietly(cacheResponse.body());
}
}

userResponse = networkResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();

if (hasBody(userResponse)) {
maybeCache();
userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
}
}

HttpStream.java


public interface HttpStream {
...

public final class Http1xStream implements HttpStream {
//-------------------------状态机的几种状态-----------------------------------------
 private static final int STATE_IDLE = 0; // Idle connections are ready to write request headers.
private static final int STATE_OPEN_REQUEST_BODY = 1;//打开请求体
private static final int STATE_WRITING_REQUEST_BODY = 2;//写请求体
private static final int STATE_READ_RESPONSE_HEADERS = 3;//读请求头
private static final int STATE_OPEN_RESPONSE_BODY = 4;//打开响应体
private static final int STATE_READING_RESPONSE_BODY = 5;//正在读响应体
private static final int STATE_CLOSED = 6;//关闭
//-------------------------状态机的几种状态-----------------------------------------

/**
* Prepares the HTTP headers and sends them to the server.
*
* <p>For streaming requests with a body, headers must be prepared <strong>before</strong> the
* output stream has been written to. Otherwise the body would need to be buffered!
*
* <p>For non-streaming requests with a body, headers must be prepared <strong>after</strong> the
* output stream has been written to and closed. This ensures that the {@code Content-Length}
* header field receives the proper value.
*/
@Override public void writeRequestHeaders(Request request) throws IOException {
httpEngine.writingRequestHeaders();
String requestLine = RequestLine.get(
request, httpEngine.getConnection().route().proxy().type());
writeRequest(request.headers(), requestLine);
}


网络截获器与应用层截获器的区别:

网络截获器:由于会处理http请求的重定位,每个interceptor会截获几次和http 服务器的request/response

应用层截获器:每个interceptor只会截获一次



ConnectionPool.java

/**
* Manages reuse of HTTP and SPDY connections for reduced network latency. HTTP requests that share
* the same {@link Address} may share a {@link Connection}. This class implements the policy of
* which connections to keep open for future use.

管理HTTP和SPDY连接复用,减少网络延迟。HTTP请求共享同一{@链接地址}或者共享一个{ @链路连接}。这个类实现了
为将来的使用保持打开状态 的策略。
 */
public final class ConnectionPool {
private final long keepAliveDurationNs;//保持活跃状态一些时间
/** * Prunes any leaked allocations and then returns the number of remaining live allocations on * {@code connection}. Allocations are leaked if the connection is tracking them but the * application code has abandoned them. Leak detection is imprecise and relies on garbage * collection.
清理虽有的泄露的配置并返回剩余的活分配{ @代码连接数}。如果连接是跟踪他们,但应用程序代码已经放弃了他们,那么这种
分配时泄露的。对于泄漏的检测是不精确的,他依赖于垃圾收
*/ private int pruneAndGetAllocationCount(RealConnection connection, long now) { List<Reference<StreamAllocation>> references = connection.allocations; for (int i = 0; i < references.size(); ) { Reference<StreamAllocation> reference = references.get(i); if (reference.get() != null) { //统计正常的分配的个数 i++; continue; } // We've discovered a leaked allocation. This is an application bug. Internal.logger.warning("A connection to " + connection.route().address().url() + " was leaked. Did you forget to close a response body?"); references.remove(i); connection.noNewStreams = true; //将连接设为不能加入流,我们在前面提到,noNewStream为true 的链接会被回收 // 如果这是最后的配置,连接应立即驱逐 if (references.isEmpty()) { connection.idleAtNanos = now - keepAliveDurationNs;//空闲时间为五分钟之前,那么就是说你的空闲时间已经被用完
//了,就是说这应该被移除了
 return 0; } } return references.size(); }}

参考文章:
http://blog.csdn.net/lmj623565791/article/details/4791108


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络 框架 android