如何控制okHttpClient连接大小?

时间:2016-03-04 23:30:47

标签: java android future okhttp

我正在调试Android应用中的问题。我发现根本原因是文件描述符超出了限制。经过进一步调查后,我发现应用程序的插槽太多了。我使用OkHttpClient 2.5进行所有网络通信,因此我想知道如何限制连接池大小。以下是我的代码段:

    OkHttpClient okHttpClient = new OkHttpClient().setConnectTimeout(TIMEOUT);
    ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS,
                                                       KEEP_ALIVE_DURATION_MS);
    okHttpClient.set(connectionPool);

    @RequireArgsConstructor
    public HttpEngineCallable implements Callable<IHttpResponse>
    {
      private final String url;

      public IHttpResponse call () throws Exception 
      {
         try
        {
           Request request = Request.Builder().url(url).build();
           Call call = okHttpClient.newCall(request);
           Response rawResponse = call.execute();
           return new OkHttpResponse(rawResponse);
        }
        catch (Exception e)
        {
           throw new IllegalStateException(e);
        }
    }  

    private final Function<IHttpResponse, T> httpResponseParser = new Function<IHttpResponse, T>()
    {
        @Nullable
        @Override
        public T apply(@Nullable IHttpResponse httpResponse)
        {
            if(httpResponse == null)
            {
               return null;
            }

            InputStream stream = httpResponse.getBody();
            JsonParser parser = null;
            T result = null;

            try
            {
               parser = jsonFactory.createParser(stream);
               result = strategy.parseData(parser);
            }
            catch (Exception e)
            {
               log.error("Unable to convert {} with {}.", stream, strategy, e);
            }
            finally
            {
               IOUtils.closeQuietly(parser);
               IOUtils.closeQuietly(stream);
            } 

          return result;
        }
     };

     Future<T> future = executorService.submit(new HttpEngineCallable(url));
     Future<V> finalFuture = Futures.transform(future, httpResponseParser, executorService);

     T result = timeoutExecutorService.submit(new Runnable() 
     {
        try
        { 
          T result = finalFuture.get(CLIENT_TIMEOUT, TIMEUNIT)
          if (result == null)
          { 
            notify onFailure listeners
          }
          else
          {
            notify onSuccess Listeners
          }
        }
        catch(Exception ex)
        {
          notify onFailure listeners
        }
     } 

所以我对这个实现有几个问题:

  1. 我的CLIENT_TIMEOUT比OkHttp ConnectTimeout短。如果我的finalFuture.get(CLINT_TIMEOUT, TIMEUNIT)抛出超时异常,那么解析器函数中的finally块是否仍会被执行?我指望它关闭我的联系。
  2. 如何限制ConnectionPool的大小?如果连接超出限制,我是否可以自动回收最旧的连接?

1 个答案:

答案 0 :(得分:6)

我们遇到了类似的问题,有太多打开的文件描述符导致我们的应用程序崩溃。

问题是我们为每个请求创建了一个OkHttpClient。默认情况下,每个OkHttpClient都附带自己的连接池,这当然会破坏连接/线程/文件句柄的数量,并阻止在池中正确重用。

我们通过在单例中手动创建全局ConnectionPool ,然后将其传递给构建实际OkHttpClient的OkHttpClient.Builder对象来解决问题。

...
builder.connectionPool(GLOBAL_CONNECTION_POOL);
OkHttpClient client = builder.build();
...

这仍允许使用OkHttpClient.Builder进行每请求配置,并确保所有OkHttpClient实例仍在使用公共连接池。 然后我们能够正确调整全局连接池的大小。