Google provides two different examples of using HttpURLConnection - Should we call HttpURLConnection disconnect or InputStream close?

Google provides 2 different examples of using the HttpURLConnection .

Call InputStream close

http://developer.android.com/training/basics/network-ops/connecting.html

 // Given a URL, establishes an HttpUrlConnection and retrieves // the web page content as a InputStream, which it returns as // a string. private String downloadUrl(String myurl) throws IOException { InputStream is = null; // Only display the first 500 characters of the retrieved // web page content. int len = 500; try { URL url = new URL(myurl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000 /* milliseconds */); conn.setConnectTimeout(15000 /* milliseconds */); conn.setRequestMethod("GET"); conn.setDoInput(true); // Starts the query conn.connect(); int response = conn.getResponseCode(); Log.d(DEBUG_TAG, "The response is: " + response); is = conn.getInputStream(); // Convert the InputStream into a string String contentAsString = readIt(is, len); return contentAsString; // Makes sure that the InputStream is closed after the app is // finished using it. } finally { if (is != null) { is.close(); } } } 

HttpURLConnection disconnect call

http://developer.android.com/reference/java/net/HttpURLConnection.html

  URL url = new URL("http://www.android.com/"); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); try { InputStream in = new BufferedInputStream(urlConnection.getInputStream()); readStream(in); finally { urlConnection.disconnect(); } } 

To leak resources and evaluate performance (no need to configure a network connection from scratch, since my application will work with the same server most of the time), we must

  • Only call HttpURLConnection disconnect .
  • Call only InputStream close .
  • Calling both HttpURLConnection disconnect and InputStream close (I have not seen such an official example yet).
+5
source share
2 answers

According to Oracle Java, calling disconnect() can close the underlying socket connection if the connection is idle (does not retrieve anything). This means that other server requests are unlikely in the near future, using the same HttpUrlConnection instance. You will need to open a new socket connection by creating another HttpUrlConnection .

However, Google has modified the HttpUrlConnection so that socket connections can be reused. On Android, the underlying Socket used by the HttpUrlConnection can be stored and reused for multiple requests. If you select disconnect after completing your request, it can send the socket to the pool containing other unoccupied connections ready for reuse. The system reduces latency.

From the documentation :

Unlike other Java implementations, it will not necessarily be closed which can be reused. You can turn off all reuse connections by setting the http.keepAlive system property to false before issuing any HTTP requests.

So, you must call disconnect to release resources (streams and sockets), but some of the freed resources can be reused (that is, the socket will go into the idle socket pool, ready for the next instance of HttpUrlConnection reuse).

As for why the first example did not call disconnect() , this is a way to reuse a Java connection (I think it was a while). What the author did was manually close the InputStream connection and left the connector open and unoccupied for reuse. The second example shows the correct path on Android.

In conclusion : calling disconnect() on Android will close any InputStream or OutputStream used to connect, and can send a socket used to connect to the pool, ready for reuse for other requests. So, if you call disconnect() , there is no need to call InputStream#close() .

+6
source

Both close and disconnect methods release the connection if it is not already issued with the following two differences:

  • close throws method IOException . Therefore, in the first example, the signature of the downloadUrl's method has throws IOException . Where the disconnect method throws no exceptions.
  • Calling the close method ensures that any future closed connection references, such as read , will result in an IOException .

The most important design fact in the implementation of Android HttpURLConnection :

The connection is made when the last bit of the response is used. When the answer is fully read, the connection will be released and will be immediately merged.

In the image below, you can see the connection and connectionReleased variables, respectively, null and true , as soon as all the data has been read. In this case, the disconnect call does not matter, the close call simply provides future calls with closed IOException links.

enter image description here

If data is still available in the InputStream , you must call close or disconnect to release the connection explicitly. In this case, the connection is not reused , and the underlying socket connection also closes. This is done in the expectation that additional data may appear in the InputStream.

You can see in the code snippets below that both disconnect and close will finally call httpEngine.release(false) , which will close the connection without adding a connection pool.

disable implementation:

 @Override public final void disconnect() { // Calling disconnect() before a connection exists should have no effect. if (httpEngine != null) { httpEngine.release(false); } } 

close :

 @Override public void close() throws IOException { if (closed) { return; } closed = true; if (bytesRemaining != 0) { unexpectedEndOfInput(); } } 

unexpectedEndOfInput :

 protected final void unexpectedEndOfInput() { if (cacheRequest != null) { cacheRequest.abort(); } httpEngine.release(false); } 

version :

 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; } } 

Summary:

  • A connection is automatically issued to the connection pool as soon as the last bit of the response is used.
  • If an IOException will be handled by the method acting on the InputStream , use disconnect . If an IOException will be thrown by the caller of a method running on an InputStream , use close . Remember close ensures that an IOException will be thrown when the read operation is performed on a closed connection in the future.
+3
source

Source: https://habr.com/ru/post/971832/


All Articles