Android 我们是否需要使用HttpURLConnection';引发IOException时的错误流

Android 我们是否需要使用HttpURLConnection';引发IOException时的错误流,android,Android,根据Oracle Java的技术指南,当抛出IOException时,我们应该使用HttpURLConnection的错误流 你能做些什么来维持生命?不要放弃连接 通过忽略响应体。这样做可能会导致TCP空闲 连接。当它们不存在时,需要进行垃圾收集 引用时间更长 如果getInputStream()成功返回,请读取整个响应 身体 从HttpURLConnection调用getInputStream()时,如果 IOException发生时,捕获异常并调用getErrorStream()以 获取响

根据Oracle Java的技术指南,当抛出
IOException
时,我们应该使用
HttpURLConnection
的错误流

你能做些什么来维持生命?不要放弃连接 通过忽略响应体。这样做可能会导致TCP空闲 连接。当它们不存在时,需要进行垃圾收集 引用时间更长

如果getInputStream()成功返回,请读取整个响应 身体

从HttpURLConnection调用getInputStream()时,如果 IOException发生时,捕获异常并调用getErrorStream()以 获取响应主体(如果有)

读取响应主体会清理连接,即使您没有 对响应内容本身感兴趣。但是如果反应体是 长,你不感兴趣的其余部分后,看到了 开始时,可以关闭InputStream。但是你需要意识到 可能会有更多的数据。因此,连接可能不正确 可以重新使用

以下是符合上述建议的代码示例:

下面是代码示例

try {
        URL a = new URL(args[0]);
        URLConnection urlc = a.openConnection();
        is = conn.getInputStream();
        int ret = 0;
        while ((ret = is.read(buf)) > 0) {
          processBuf(buf);
        }
        // close the inputstream
        is.close();
} catch (IOException e) {
        try {
                respCode = ((HttpURLConnection)conn).getResponseCode();
                es = ((HttpURLConnection)conn).getErrorStream();
                int ret = 0;
                // read the response body
                while ((ret = es.read(buf)) > 0) {
                        processBuf(buf);
                }
                // close the errorstream
                es.close();
        } catch(IOException ex) {
                // deal with the exception
        }
}

这是否适用于Android平台?因为我在大多数Android代码示例中都没有看到这种技术。

如果您对向用户显示错误消息不感兴趣,请关闭
输入流
或在
中调用
HttpURLConnection
上的
断开连接
,而不读取错误消息。这是您在大多数示例中看到的

在浏览HttpURLConnection的实现时,我在其中一篇文章中遇到了以下评论。这可能就是为什么在不读取所有数据的情况下关闭连接的原因

当连接意外关闭时,应调用此命令 使缓存项无效并阻止HTTP连接 重复使用。HTTP消息以串行方式发送,因此无论何时 无法读取完成,无法读取后续消息 必须放弃和连接中的任何一个

根据Android实现的
HttpURLConnection
,如果出现异常:

  • 如果未读取错误并且关闭了
    InputStream
    ,则连接将被视为不可重用并关闭
  • 如果读取错误,然后关闭
    InputStream
    ,则连接将被视为可重用,并添加到连接池中
在下图中可以看到,只要读取了所有数据,变量
connection
connectionReleased
就分别设置为
null
true
。请注意,
getErrorStream
返回
InputStream
,因此它在异常场景中也有效

代码分析:让我们看一看专门的InputStream实现。以下是
close
方法的实现:

 @Override public void close() throws IOException {
    if (closed) {
        return;
    }
    closed = true;
    if (bytesRemaining != 0) {
        unexpectedEndOfInput();
    }
 }
protected final void unexpectedEndOfInput() {
    if (cacheRequest != null) {
        cacheRequest.abort();
    }
    httpEngine.release(false);
}
实例变量
byteslaining
包含要读取的
InputStream
上仍然可用的字节数。以下是方法实现:

 @Override public void close() throws IOException {
    if (closed) {
        return;
    }
    closed = true;
    if (bytesRemaining != 0) {
        unexpectedEndOfInput();
    }
 }
protected final void unexpectedEndOfInput() {
    if (cacheRequest != null) {
        cacheRequest.abort();
    }
    httpEngine.release(false);
}
下面是方法的实现。在
HttpURLConnection
实例上调用
disconnect
,将调用此
release
方法,并将
false
作为参数。 最后一次
if
检查可确保连接是否需要关闭或添加到连接池中以供重用。

public final void release(boolean reusable) {
    // If the response body comes from the cache, close it.
    if (responseBodyIn == cachedResponseBody) {
        IoUtils.closeQuietly(responseBodyIn);
    }
    if (!connectionReleased && connection != null) {
        connectionReleased = true;
        // We cannot reuse sockets that have incomplete output.
        if (requestBodyOut != null && !requestBodyOut.closed) {
            reusable = false;
        }
        // If the headers specify that the connection shouldn't be reused, don't reuse it.
        if (hasConnectionCloseHeader()) {
            reusable = false;
        }
        if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
            reusable = false;
        }
        if (reusable && responseBodyIn != null) {
            // We must discard the response body before the connection can be reused.
            try {
                Streams.skipAll(responseBodyIn);
            } catch (IOException e) {
                reusable = false;
            }
        }
        if (!reusable) {
            connection.closeSocketAndStreams();
            connection = null;
        } else if (automaticallyReleaseConnectionToPool) {
            HttpConnectionPool.INSTANCE.recycle(connection);
            connection = null;
        }
    }
}
您共享的代码处理IOException,读取并关闭错误流,确保连接可重用,并将其添加到连接池中。从
InputStream
读取所有数据时,
连接将添加到连接池中。以下是
fixedlenghthinputstream
read
方法实现:

@Override public int read(byte[] buffer, int offset, int count) throws IOException {
        Arrays.checkOffsetAndCount(buffer.length, offset, count);
        checkNotClosed();
        if (bytesRemaining == 0) {
            return -1;
        }
        int read = in.read(buffer, offset, Math.min(count, bytesRemaining));
        if (read == -1) {
            unexpectedEndOfInput(); // the server didn't supply the promised content length
            throw new IOException("unexpected end of stream");
        }
        bytesRemaining -= read;
        cacheWrite(buffer, offset, read);
        if (bytesRemaining == 0) {
            endOfInput(true);
        }
        return read;
    }
byteslaining
变量变为0时,调用该变量,该变量将进一步调用
release
方法和
true
参数,以确保连接被池化

protected final void endOfInput(boolean reuseSocket) throws IOException {
        if (cacheRequest != null) {
            cacheBody.close();
        }
        httpEngine.release(reuseSocket);
    }

如果它是为Java编写的,那么它是为Android平台绑定的。

我在Android中看到的HttpURLConnection示例只是在finally块中执行
disconnect()
。从文档中,“断开连接会释放连接所持有的资源,以便它们可以关闭或重新使用。”我想没有“保持活动”。这可能是你问题的答案,我已经在下面的回答中写下了我的想法。如果您需要进一步澄清,请告诉我。