我有3个AsyncTasks
和1个ProgressBar
。当任何一个任务执行时,我希望进度条可见,并且当它们全部完成时,进度条不可见。
在Java中,有ExecutorService::isTerminated
来检查是否所有可运行的任务已完成,但Android没有它。
更新:3个任务同时执行。
图示。
我有3个AsyncTasks
和1个ProgressBar
。当任何一个任务执行时,我希望进度条可见,并且当它们全部完成时,进度条不可见。
在Java中,有ExecutorService::isTerminated
来检查是否所有可运行的任务已完成,但Android没有它。
更新:3个任务同时执行。
图示。
好的图形。但是恐怕没有内置机制可以实现这一点。您将不得不自己实现它。您可以使用以下几种解决方案-
尝试使用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);
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
}
一个简单的解决方法是使用三个布尔变量,每个都对应一个AsyncTask,然后相应地进行检查。
更好的方法是创建一个扩展AsynTask的单独类,并定义一个回调接口,在onPostExecute中触发它。
正如你所知道的,当一个 AsyncTask
结束时(当调用 onPostExecute
时):
其中一种解决方案是创建一个方法 setProgressBarVisible()
来保持一个计数器,在第一次调用时设置可见性,并且还有一个方法 setProgressBarInvisible()
来递减计数器并在零时将进度条设置为不可见。
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);
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();
}
:-? 我认为这只是一个技巧。您将在每个Asyntask
的onPostExecute
返回一些消息并进行比较。(此消息可以包含时间,例如)
自 API 级别 24 开始,CompletableFuture 官方支持已经引入。
在 Java 8 中也可以使用 这里。
您可以简单地使用以下代码:
taskA.thenCombine(taskB).thenCombine(taskC)
当你想在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));
}
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
是的,在生产环境中,你应该有点偏执并进行所有这些检查 :)
这就是为什么你可以使用EventBus,如果你的UI死了 - 没关系。
试试这个,或许可以帮到你...
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);