检查所有 AsyncTask 是不是已完成
Posted
技术标签:
【中文标题】检查所有 AsyncTask 是不是已完成【英文标题】:Check if all AsyncTasks have finished检查所有 AsyncTask 是否已完成 【发布时间】:2011-10-18 23:26:28 【问题描述】:我有 3 个AsyncTasks
和 1 个ProgressBar
。我希望当任何任务执行时,进度条是可见的,当所有任务完成时,进度条是不可见的。
在 Java 中,有 ExecutorService::isTerminated
来检查是否所有可运行对象都已完成,但 android 没有。
更新:3 个任务同时执行。
图。
【问题讨论】:
试试我在下面提供的解决方案,它就像一个魅力 【参考方案1】:漂亮的图形。但恐怕没有内置机制。你必须自己实现它。您可以使用的解决方案很少 -
-
保留对所有 3 个任务的引用。当任务完成时,检查其他两个任务是否也完成,如果是,则关闭进度对话框,如果没有,则等待其他任务完成并再次检查。确保在完成后释放参考。
如果您不想保留参考存储,请使用计数器。当任务完成时,增加计数器并检查它是否等于 3。如果所有任务都完成并且你完成了。如果您实施此操作,请确保同步对计数器的访问。
【讨论】:
【参考方案2】:尝试使用 AsyncTask.getStatus()。这工作得很好。请参考下面的示例代码。
List<AsyncTask<String, String, String>> asyncTasks = new ArrayList<AsyncTask<String, String, String>>();
AsyncTask<String, String, String> asyncTask1 = new uploadTask().execute(string);
AsyncTask<String, String, String> asyncTask2 = new downloadTask().execute(string);
AsyncTask<String, String, String> asyncTask3 = new createTask().execute(string);
asyncTasks.add(asyncTask1);
asyncTasks.add(asyncTask2);
asyncTasks.add(asyncTask3);
您可以稍后循环 AsyncTaskList 并找到每个任务的状态,如下所示。
for(int i=0;i<asyncTasks.size();i++)
AsyncTask<String, String, String> asyncTaskItem = (AsyncTask<String, String, String>)asyncTasks.get(i);
// getStatus() would return PENDING,RUNNING,FINISHED statuses
String status = asyncTaskItem.getStatus().toString();
//if status is FINISHED for all the 3 async tasks, hide the progressbar
【讨论】:
我在没有名字的情况下做了,但效果很好。谢谢!之后我确实从 ArrayList 中删除了这些项目(当状态 == 完成时),而不仅仅是检查状态。这将使更大的 asyncTasks 集更容易,比如我的 30 多个任务集..【参考方案3】:一个简单的解决方法是为每个 AsyncTask 使用三个布尔变量,然后相应地检查它们。
更好的方法是创建一个单独的类来扩展 AsynTask 并定义一个在 onPostExecute 中触发的回调接口。
【讨论】:
【参考方案4】:创建一个字段来保存所有任务:
private ArrayList<htmlDownloaderTask> mTasks;
以这种方式开始你的任务:
HtmlDownloaderTask = new HtmlDownloaderTask(page.getHtml());
task.execute(page.getUrl());
//if you want parallel execution try this:
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,page.getUrl());
mTasks.add(task);
关于 MyAsyncTask 的 onPostExecute:
int unfinishedTasks = 0;
for (HtmlDownloaderTask myDT : mTasks)
if(!(myDT.getStatus() == AsyncTask.Status.FINISHED))
unfinishedTasks++;
if (unfinishedTasks == 1)
//We are all done. 1 Because its the current one that hasnt finished post execute
callWhateverMethod();
【讨论】:
【参考方案5】:您知道AsyncTask
何时结束(当onPostExecute
被调用时):
一种解决方案可能是创建一个方法setProgressBarVisible()
保持计数器在第一次调用时设置可见,以及一个方法setProgressBarInvisible()
减少计数器并且在零时设置进度条不可见。
【讨论】:
【参考方案6】::-?我认为这只是一个把戏。您将在每个Asyntask
的onPostExecute
返回一些消息并进行比较。 (例如,此消息可以包含时间)
【讨论】:
【参考方案7】:自 API 级别 24 起引入了对 CompletableFuture 的官方支持。
它也可用于 Java 8 here。
可以简单地使用类似的东西:
taskA.thenCombine(taskB).thenCombine(taskC)
【讨论】:
【参考方案8】:我会简单地通过onPostExecute()
通知它,参考onPostExecute and 4 steps in the document for detail,您可以使用EventBus
做一些订阅事情。
【讨论】:
【参考方案9】:当您想在 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 死了 - 无论如何。
【讨论】:
【参考方案10】:试试这个,也许能帮到你……
final ImageUploader _upload = new ImageUploader();
_upload.setValue(getApplicationContext(), _imagepath, _urlphp);
_upload.execute();
Runnable _run;
Handler _h2;
_run = new Runnable()
public void run()
_h2 = new Handler();
_h2.postDelayed(this, 1000);
Toast.makeText(getApplicationContext(), "not finished", Toast.LENGTH_LONG).show();
if (_upload.getStatus() == AsyncTask.Status.FINISHED)
Toast.makeText(getApplicationContext(), "finished", Toast.LENGTH_LONG).show();
_h2.removeCallbacks(_run);
;
_h2 = new Handler();
_h2.postDelayed(_run, 1);
【讨论】:
以上是关于检查所有 AsyncTask 是不是已完成的主要内容,如果未能解决你的问题,请参考以下文章
ProgressDialog.show() - Activity 已泄露窗口