如何在 AsyncTask 的 doInBackground() 中获取 WeakReference

How to get WeakReference in doInBackground() of AsyncTask

我有一个名为 RetrieveCoverImageTask 的 class。它从 Track 实例中的 URL 检索实际封面图像:

private class RetrieveCoverImageTask extends AsyncTask<Track, Void, Void> {

    private WeakReference<Context> context;

    RetrieveCoverImageTask(Context context) {
        this.context = new WeakReference<>(context);
    }

    // V1
    @Override
    protected Void doInBackground(Track... tracks) {
        Context context = this.context.get();
        if (context != null) {
            for (Track track : tracks) {
                try {
                    Bitmap bmp = Picasso.with(context).load(track.getCoverUrl()).get();
                    if (bmp != null) {
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
                        track.setCoverImage(stream.toByteArray());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    // V2
    @Override
    protected Void doInBackground(Track... tracks) {
        for (Track track : tracks) {
            try {
                Context context = this.context.get();
                if (context != null) {
                    Bitmap bmp = Picasso.with(context).load(track.getCoverUrl()).get();
                    if (bmp != null) {
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
                        track.setCoverImage(stream.toByteArray());
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

来自 Activity 的示例调用如下:

new RetrieveCoverImageTask(context).execute(track1, track2, track3);

首先,我做了V1。然后,我想到 Picasso 的图像检索需要时间,同时调用 Activity 可能会变为 null,因此,我必须在 for 循环的每次迭代开始时获取上下文。这就是我实现 V2 的方式。

doInBackground() 哪个版本高效且不易出错? V1 还是 V2?

效率可能不是这里最大的问题。 V2比较安全,但是整体不是很"elegant"。使用 RxJava 进行设置会容易得多。你不需要 WeakReferences。关键是在上下文无效时处理您的订阅(例如 onDestroy()),您将保存 null 的检查。

此外,您可能希望使用一种方法来获取不涉及 picasso 的 bmp,因此不需要上下文。或者你使用只要你的应用程序是运行就存在的应用程序上下文,所以你不需要空检查

WeakReference.get正确。

如果您想使用 Picasso,您可以直接在 View 上执行(可能是 onBindViewholder),因为它已经在后台执行了。

如果你想使用一个任务,你需要下载流而不是使用 URLConnection 来高效地下载流,或者 OkHttp(最新版本,因为它作为 URLConnection 嵌入)

在异步任务中使用 Picasso 毫无意义,因为 Picasso 无论如何都会在不同的线程上异步加载图像。此外,您将位图存储在变量中,这会消耗大量内存,因为位图很重,即使不需要它们,它们也会全部存储在 ram 中。正如 Marcos Vasconcelos 所指出的,更好的方法是在您的 ViewHolder 中直接使用 Picasso。