Android okhttp3文件描述符过多问题

Android okhttp3文件描述符过多问题,android,okhttp,file-descriptor,okhttp3,Android,Okhttp,File Descriptor,Okhttp3,我有一个图像“管理器”,可以下载图像。 在此之前,我使用毕加索图书馆,如下所示 class DownloadImage implements Runnable { String url; Context context; public DownloadImage(String url, Context context) { this.url = url; this.context = context; } @Overr

我有一个图像“管理器”,可以下载图像。 在此之前,我使用毕加索图书馆,如下所示

class DownloadImage implements Runnable {

    String url;
    Context context;

    public DownloadImage(String url, Context context) {
        this.url = url;
        this.context = context;
    }

    @Override
    public void run() {
        try {
            String hash = Utilities.getSha1Hex(url);
            FileOutputStream fos = context.openFileOutput(hash, Context.MODE_PRIVATE);
            Bitmap bitmap = Picasso.with(context)
                    .load(url)
                    .resize(1024, 0) // Height 0 to ensure the image is scaled with respect to width - http://stackoverflow.com/a/26782046/1360853
                    .onlyScaleDown()
                    .memoryPolicy(MemoryPolicy.NO_CACHE)
                    .get();

            // Writing the bitmap to the output stream
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
            fos.close();
            bitmap.recycle();
        } catch (IOException e) {
            Timber.e(e, "For url %s", url);
        } catch (OutOfMemoryError e) {
            Timber.e(e, "out of memory for url %s", url);
        }
    }
}
但这会创建一个位图对象,它不仅消耗大量内存,而且速度相当慢,而且不必要

我已将此Runnable修改为使用
okhttp3

class DownloadImage implements Runnable {

    String url;
    Context context;

    public DownloadImage(String url, Context context) {
        this.url = url;
        this.context = context;
    }

    @Override
    public void run() {
        try {
            String hash = Utilities.getSha1Hex(url);
            final FileOutputStream fos = context.openFileOutput(hash, Context.MODE_PRIVATE);
            Request request = new Request.Builder().url(url).build();
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    try {
                        fos.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Sink sink = null;
                    BufferedSource source = null;
                    try {
                        source = response.body().source();
                        sink = Okio.sink(fos);
                        source.readAll(sink);
                    } catch (Exception e) {
                        Timber.e(e, "Downloading an image went wrong");
                    } finally {
                        if (source != null) {
                            source.close();
                        }
                        if (sink != null) {
                            sink.close();
                        }
                        fos.close();
                        okHttpClient.connectionPool().evictAll(); // For testing
                    }
                }
            });
        } catch (IOException e) {
            Timber.e(e, "For url %s", url);
        }
    }
}
虽然这种方法比前一种方法快得多,但对于大量图像,我得到了
A/libc:FORTIFY\u SOURCE:FD\u SET:file descriptor>=FD\u SETSIZE。调用abort()。
后接一个微转储,这意味着打开的文件描述符太多

为了测试起见,我添加了
okHttpClient.connectionPool().executeAll();//用于测试
行,但这不起作用。 我还尝试了设置
builder.connectionPool(新的connectionPool(4500,TimeUnit.millides))在构建
okHttpClient
时,但这也没有起到任何作用。 我也知道

我似乎关闭了所有流/汇/源,那么这里发生了什么?

可运行项使用其
execute
函数添加到
ThreadPoolExecutor
,该函数创建如下:

// Sets the amount of time an idle thread waits before terminating
private static final int KEEP_ALIVE_TIME = 500;
// Sets the Time Unit to milliseconds
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.MILLISECONDS;
private static int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

// A queue of Runnables
private final BlockingQueue<Runnable> mDecodeWorkQueue;
private OkHttpClient okHttpClient;

ThreadPoolExecutor mDecodeThreadPool;

public ImageManager() {
    // Instantiates the queue of Runnables as a LinkedBlockingQueue
    mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();

    // Creates a thread pool manager
    mDecodeThreadPool = new ThreadPoolExecutor(
            NUMBER_OF_CORES,       // Initial pool size
            NUMBER_OF_CORES,       // Max pool size
            KEEP_ALIVE_TIME,
            KEEP_ALIVE_TIME_UNIT,
            mDecodeWorkQueue);

}
//设置空闲线程在终止前等待的时间量
私有静态最终int保持活动时间=500;
//将时间单位设置为毫秒
私有静态最终时间单位KEEP_ALIVE_TIME_UNIT=TimeUnit.ms;
私有静态int NUMBER_OF_CORES=Runtime.getRuntime().AvailableProcessor();
//一队跑龙套的人
私有最终阻塞队列mDecodeWorkQueue;
私人OkHttpClient OkHttpClient;
线程池执行器mDecodeThreadPool;
公共图像管理器(){
//将可运行队列实例化为LinkedBlockingQueue
mDecodeWorkQueue=新建LinkedBlockingQueue();
//创建线程池管理器
mDecodeThreadPool=新线程池执行器(
内核的数量,//初始池大小
内核的数量,//最大池大小
让你活下去,
让你活下去时间单位,
mDecodeWorkQueue);
}

通过在OnResponse正文中创建并使用
文件输出流来解决此问题,这样在请求完成时它不会打开。

您能否分享解决此问题的代码更改差异,以使上述解决方案更清晰?