最近遇到了這樣一個問題,在Android開啓StrictMode的時候,會拋出一個異常以下:java
04-01 16:07:56.864: E/StrictMode(26867): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
04-01 16:07:56.864: E/StrictMode(26867): java.lang.Throwable: Explicit termination method 'close' not called
04-01 16:07:56.864: E/StrictMode(26867): at dalvik.system.CloseGuard.open(CloseGuard.java:184)
04-01 16:07:56.864: E/StrictMode(26867): at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:271)
04-01 16:07:56.864: E/StrictMode(26867): at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:598)
04-01 16:07:56.864: E/StrictMode(26867): at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:560)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.io.SocketInputBuffer.(SocketInputBuffer.java:70)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:172)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
04-01 16:07:56.864: E/StrictMode(26867): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
異常大概是說資源沒有釋放,須要顯示的調用close方法。從log上看是網絡訪問時出現的問題(我使用的是HttpClient)。
可是在關閉StrictMode的時候程序能夠徹底正常的運行。緣由何在呢?
經過查看HttpClient官方文檔發現,在HttpClient請求結束後須要銷燬HttpEntity,這樣纔可使網絡鏈接返回鏈接池等待下一次重用(若是不須要重用的話也能夠直接關掉鏈接)。
官方推薦的HttpEntity銷燬方法:HttpEntity#consumeContent
在查看代碼時發現,HttpEntity並無銷燬。但是其餘網絡請求部分的HttpEntity也都沒有銷燬,爲何只有這一個網絡請求會報錯呢?並且代碼中有監聽網絡超時並關掉鏈接的處理,爲何還會出現這個問題呢?
仔細查看發現,出現問題的部分與其餘部分稍有不一樣。出現問題的網絡請求在解析響應的時候,並不須要解析Entity,他的響應結果是放在Headers裏面的。也就是說這部分代碼在請求結束的時候沒有調用HttpResponse#getEntity#getContent方法。
查看HttpClient文檔發現getContent方法也可使Entity銷燬。
因此就是這個緣由使StrictMode拋出資源未釋放的異常。
由於有了網絡超時監聽的處理,因此在關閉StrictMode的時候並不會出現什麼問題,由於沒有釋放的鏈接會等到網絡超時的時候會被釋放。
在使用HttpClient時必定要注意資源的釋放。即便有網絡超時自動關閉鏈接的監聽,StrictMode也會報告沒有釋放資源的異常,由於鏈接不會當即釋放,須要等待超時時間的到來纔會release,這樣影響了程序的性能。
附HttpClient源碼分析:
1.BasicHttpEntity#getContent源碼:
在getContent方法中將contentObtained置爲true;標記content已經被獲取過了,在其餘地方檢測這個標記,若是資源被獲取過,那麼就會release掉這個鏈接。
2.BasicHttpEntity#consumeContent源碼:
關閉content(content類型爲InputStream)
3.EntityUtils#toString
在EntityUtils#toString方法的最後直接進行了reader.close();所以直接調用EntityUtils#toString方法後至關於調用了HttpEntity#consumeContent方法