如何在 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。
我有一个名为 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。