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);
後で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
}
簡単な回避策は、AsyncTaskごとに1つずつ3つのブール変数を使用し、それに応じてそれらをチェックすることです。
より良いアプローチは、AsynTaskを拡張し、onPostExecuteで起動されるコールバックインターフェイスを定義する別のクラスを作成することです。
すべてのタスクを保持するフィールドを作成します。
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();
}
AsyncTask
がいつ終了するか(onPostExecute
が呼び出されるとき)をご存知のとおり:1つの解決策は、カウンターを保持するメソッドsetProgressBarVisible()
を作成し、最初にセットを呼び出すことです。表示され、カウンタを減らし、ゼロの場合はプログレスバーを非表示に設定するメソッドsetProgressBarInvisible()
。
onPostExecute()
で通知するだけです。 onPostExecuteと詳細についてはドキュメントの4つのステップ を参照してください。EventBus
を使用してサブスクライブを行うことができます。
:-?ただのトリックだと思います。各onPostExecute
のAsyntask
にメッセージを返し、それを比較します。 (たとえば、このメッセージには時間を含めることができます)
CompletableFuture の公式サポートがAPIレベル24以降に導入されました。
Java 8 here でも利用できます。
次のようなものを使用するだけで使用できます。
taskA.thenCombine(taskB).thenCombine(taskC)
これは、THREAD_POOL_EXECUTORで一連のAsynTasksを実行する場合によくある質問です。 .execute()
を呼び出すだけで、すべてのタスクが1つずつ実行される場合よりもはるかに高速です。したがって、複数のジョブがあり、オブジェクトが相互に依存していない場合は、スレッドプールで実行してみてください。
しかし、問題は、すべてのタスクが完了したことをどうやって知ることができるかということです。
AsyncTaskには組み込みのメソッドがないため、少し回避策を講じる必要があります。
私の場合、静的HashmapフィールドをAsynctaskクラスに追加して、開始および終了したすべてのタスクを追跡しました。マップのボーナスとして、現在進行中のタスクをいつでも知ることができます。
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
この地図にアクセスするための簡単な3つの方法。 重要:同期する必要があります
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を使用してイベントをフラグメントに送信しましたが、コールバックを使用できます。この場合、callbackMethodを使用してインターフェースを作成する必要があります。フラグメント(イベントを待機しているUIコンポーネント)はこのインターフェースを実装し、そのメソッドを持っている必要があります。次に、AsyncTaskコンストラクターで、フラグメントを引数として取得し、それへの参照を保持します。これにより、すべてが完了したときに、フラグメントのコールバックメソッドを呼び出すことができます。
しかし、私はそのようなアプローチが好きではありません。まず、フラグメントが死んでいるときにメモリリークが発生するため、フラグメント(またはその他のUI)の参照をWeakReferenceラッパーに保持する必要があります(ただし、AsyncTaskに参照があるため、メモリに保持されます)。また、多くのチェックを行う必要があり、次のようになります。
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
うん、本番環境では少し妄想的で、これらすべてのチェックを行う必要があります:)
そのため、EventBusを使用でき、UIが機能していない場合は何でもかまいません。