检查所有异步任务是否已经完成

21

我有3个AsyncTasks和1个ProgressBar。当任何一个任务执行时,我希望进度条可见,并且当它们全部完成时,进度条不可见。

在Java中,有ExecutorService::isTerminated来检查是否所有可运行的任务已完成,但Android没有它。

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

图示。 enter image description here


尝试一下我在下面提供的解决方案,它非常有效。 - Jagadeesh
10个回答

24

好的图形。但是恐怕没有内置机制可以实现这一点。您将不得不自己实现它。您可以使用以下几种解决方案-

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

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
 }

我没有使用名称,但完美地解决了它。谢谢!我之后从ArrayList中删除了项目(当状态==完成时),而不仅仅是检查状态。这将使在类似于我的30多个asyncTasks集合的较大集合上更容易。 - Mathieu Brouwers

2

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

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


1

正如你所知道的,当一个 AsyncTask 结束时(当调用 onPostExecute 时): 其中一种解决方案是创建一个方法 setProgressBarVisible() 来保持一个计数器,在第一次调用时设置可见性,并且还有一个方法 setProgressBarInvisible() 来递减计数器并在零时将进度条设置为不可见。


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

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

}

0

0

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


0

自 API 级别 24 开始,CompletableFuture 官方支持已经引入。

在 Java 8 中也可以使用 这里

您可以简单地使用以下代码:

taskA.thenCombine(taskB).thenCombine(taskC)

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

每次任务完成时,它都会调用onPostExecute并检查它是否是最后一个任务。如果没有剩余任务-发送一个信号表示你已经完成了。
现在,在这里我使用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死了 - 没关系。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接