检查是否所有AsyncTasks都已完成

时间:2011-08-03 10:00:42

标签: android multithreading android-asynctask android-2.2-froyo

我有3 AsyncTasks和1 ProgressBar。我希望当任何任务执行时,进度条都可见,当所有任务完成时,进度条是不可见的。

在Java中,有ExecutorService::isTerminated来检查所有runnables是否已完成,但Android没有。

更新:3个任务同时执行。

图。 enter image description here

10 个答案:

答案 0 :(得分:22)

漂亮的图形。但我担心没有建立机制。你必须自己实现它。您可以使用的解决方案很少 -

  1. 保留对所有3个任务的引用。当任务完成时,检查其他两个任务是否也完成,如果是,则关闭进度对话框,如果没有等待其他任务完成并再次检查。确保在完成后释放参考文献。
  2. 如果您不想保留参考商店的计数器。任务完成后,递增计数器并检查它是否等于3.如果所有任务都完成并且您已完成。如果实施此操作,请确保同步对计数器的访问。

答案 1 :(得分:7)

尝试使用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
 }

答案 2 :(得分:2)

一个简单的解决方法是为每个AsyncTask使用三个布尔变量,然后相应地检查它们。

更好的方法是创建一个扩展AsynTask的单独类,并定义一个在onPostExecute中触发的回调接口。

答案 3 :(得分:1)

当你知道AsyncTask何时结束(当onPostExecute被调用时)时你知道了: 一个解决方案可能是创建一个方法setProgressBarVisible(),它保持一个计数器,当第一次调用sets时可见,一个方法setProgressBarInvisible()减少计数器,当零设置进度条不可见时。

答案 4 :(得分:1)

创建一个字段来保存所有任务:

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);

on 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 :(得分:0)

: - ?我认为这只是一个技巧。您将在每个onPostExecute的{​​{1}}处返回一些消息并进行比较。 (例如,此消息可以包含时间)

答案 6 :(得分:0)

我只需在onPostExecute()通知它,参考onPostExecute and 4 steps in the document for detail即可使用EventBus进行订阅。

答案 7 :(得分:0)

自API级别24以来,我们引入了CompletableFuture的官方支持。

它也可以在Java 8中使用here

可以使用简单的用法:

taskA.thenCombine(taskB).thenCombine(taskC)

答案 8 :(得分:0)

当您想在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构造函数中向跟踪Map添加新项目,然后在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作为参数并保留对其的引用,以便在一切完成后可以调用它的回调方法。

但是我不喜欢这种方法。首先,您需要将片段(或任何其他UI)的引用保存在WeakReference包装器中,因为片段死时会发生内存泄漏(但仍保留在内存中,因为AsyncTask拥有它的引用)。 另外,您还需要进行大量检查,看起来像这样:

private boolean isAlive() {
    return mFragmentWeakReference != null
            && mFragmentWeakReference.get() != null
            && mFragmentWeakReference.get().isAdded()
            && mFragmentWeakReference.get().getActivity() != null
            && !mFragmentWeakReference.get().getActivity().isFinishing();

是的,在生产中,您应该有点偏执,并进行所有这些检查:)

这就是为什么您可以使用EventBus以及用户界面已死的原因-

答案 9 :(得分:-1)

试试这个,也许可以帮到你......

            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);