当您想在 THREAD_POOL_EXECUTOR 上运行一堆 AsynTasks 时,这是一个常见问题。这比您只调用.execute() 并且您的所有任务都一项一项完成要快得多。
因此,如果您有多个作业并且对象不依赖于彼此的状态 - 尝试在线程池上运行。
但问题是:我怎么知道我的所有任务都已完成?
AsyncTask 中没有内置方法,因此您应该做一些解决方法。
在我的例子中,我在我的 Asynctask 类中添加了一个静态 Hashmap 字段,以跟踪所有已启动和已完成的任务。作为地图的奖励,我总是可以知道当前正在进行哪个任务。
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
并提供三种访问此地图的简单方法。
重要提示:它们应该同步
public static synchronized void addTask(Uri uri){
mapOfAttachmentTasks.put(uri, true);
}
public static synchronized void removeTask(Uri uri){
mapOfAttachmentTasks.remove(uri);
}
public static synchronized boolean isTasksEmpty(){
return mapOfAttachmentTasks.isEmpty();
}
您想在 AsyncTask 构造函数中将新项目添加到跟踪地图并在 onPostExecute() 中将其删除:
public AttachmentTask(Uri uri) {
this.uri = uri;
addTask(uri);
}
@Override
protected void onPostExecute(Attachment attachment) {
removeTask(uri);
if(isTasksEmpty())
EventBus.getDefault().post(new AttachmentsTaskFinishedEvent(attachment));
}
每次任务完成时,它都会调用 onPostEexecute 并检查它是否是最后一个任务。如果没有剩余任务 - 发送信号表明您已完成。
现在,我在这里使用 EventBus 将事件发送到我的 Fragment,但您可以使用回调。在这种情况下,您应该使用 callbackMethod 创建一个接口,您的 Fragment(任何等待事件的 UI 组件)应该实现该接口并具有该方法。然后在 AsyncTask 构造函数中获取 Fragment 作为参数并保留对它的引用,以便在一切完成后调用它的回调方法。
但我不喜欢这样的做法。首先,您需要将 Fragment(或任何其他 UI)的引用保存在 WeakReference 包装器中,因为当您的 Fragment 死了(但仍保留在内存中,因为您的 AsyncTask 有它的引用)时,您会发生内存泄漏。
此外,您需要进行大量检查,它看起来像这样:
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
是的,在生产中你应该有点偏执并做所有这些检查:)
这就是你可以使用 EventBus 的原因,如果你的 UI 死了 - 无论如何。