CachingHttpClient不消耗后端HttpResponse实体导致app冻结

时间:2012-11-20 08:02:05

标签: android httpclient

我正在使用带有PoolingClientConnectionManager的HttpClient 4.2.1,我发现我的应用程序将在一些使用后开始尝试获取http连接。如果你没有使用HttpEntity,这个症状似乎是一个常见的错误,因为4.2.1依赖于关闭内容的流来返回它与池的连接。

以下是我如何组装HttpClients及其池

HttpClient standardClient = null;
HttpClient cachedClient = null;
PoolingClientConnectionManager connectionManager = null;

protected synchronized HttpClient getStandardClient() {
  if ( standardClient == null ) {
    connectionManager = new PoolingClientConnectionManager();
    connectionManager.setMaxTotal(2);
    connectionManager.closeIdleConnections(120, TimeUnit.SECONDS);
    standardClient = new DecompressingHttpClient( new DefaultHttpClient (connectionManager));
    Log.i(tag, "Creating ConnectionManager and standard http client");
  }

  return standardClient;
}

protected synchronized HttpClient getCachedClient() {
  if ( cachedClient == null ) {
    CacheConfig cacheConfig = new CacheConfig();
    cacheConfig.setMaxObjectSize( 512*1024 );
    cacheConfig.setMaxCacheEntries( 10 );

    cachedClient = new CachingHttpClient(getStandardClient(),
                                         getCacheStorage(),
                                         cacheConfig);
    Log.i(tag, "Creating CachingHttpClient");
  }

  return cachedClient;
}

如你所见,我有两个客户。缓存包装标准客户端的http客户端。

现在我发现如果我删除cachedClient并且只使用standardClient,那么池挂起和孤立连接没有任何问题。

查看CachingHttpClient的源代码,它似乎不会使用底层实体。还有其他人经历过这个吗?

任何人都可以在我的代码中看到任何错误以及我如何配置和使用HttpClient?有没有人知道我可以在我的代码中做些什么来正确地让后端实体正确使用?

顺便说一句,这就是我如何使用http客户端并使用它们......

HttpClient httpClient = cacheOkay ? getCachedClient() : getStandardClient();  
HttpResponse response = httpClient.execute(request, localContext);
HttpEntity resEntity = response.getEntity();  

int responseStatus = response.getStatusLine().getStatusCode();

byte[] responseBody = EntityUtils.toByteArray(resEntity);
EntityUtils.consume(resEntity);

此外,对于那些想知道这是在Android上的人我已经使用JarJar将HttpClient 4.2.1重新打包到备用包结构中,因此它不会与Android附带的旧版HttpClient类冲突。但是,尽管重新包装代码是100%4.2.1。我只是提到这一点,以避免在Android上运行HttpClient 4.2.1时出现任何冲突建议。

1 个答案:

答案 0 :(得分:0)

因此,在与此摔跤之后,我确信这是HttpCommons中的一个错误。该错误似乎是HttpCachingClient没有正确地使用来自后端HttpClient的HttpEntity。在我们的例子中,由于这是一个池化客户端,这可以防止每次返回池中的连接。

我的工作是确保HttpCachingClient关闭来自后端客户端的流。

以下是用于创建缓存客户端的修订代码

    protected synchronized HttpClient getCachedClient() {
      if ( cachedClient == null ) {
        CacheConfig cacheConfig = new CacheConfig();
        cacheConfig.setMaxObjectSize( 512*1024 );
        cacheConfig.setMaxCacheEntries( 10 );
        cachedClient = new CachingHttpClient(getStandardClient(),
                                             new HeapResourceFactory() {
                                               @Override
                                               public Resource generate(String requestId,InputStream instream,InputLimit limit) throws IOException {
                                                    try {
                                                      return super.generate(requestId, instream, limit);
                                                    }
                                                    finally {
                                                      instream.close();
                                                    }
                                                }
                                             },
                                             application.getCacheStorage(),
                                             application.getCacheConfig());
        Log.i(tag, "Creating CachingHttpClient");
    }

    return cachedClient;
}

所以基本上我将HeapResourceFactory子类化并添加了instream.close()以确保它使用该后端实体。