web-dev-qa-db-ja.com

すべてのAsyncTasksが終了したかどうかを確認します

3つのAsyncTasksと1つのProgressBarがあります。いずれかのタスクが実行されると進行状況バーが表示され、すべてのタスクが完了すると進行状況バーが非表示になります。

Javaには、すべてのランナブルが終了したかどうかを確認するためのExecutorService::isTerminatedがありますが、Androidにはありません。

更新:3つのタスクが同時に実行されます。

図。 enter image description here

21
emeraldhieu

素敵なグラフィック。しかし、私はこれのための組み込みのメカニズムがないのではないかと心配しています。自分で実装する必要があります。使用できるソリューションはほとんどありません-

  1. 3つのタスクすべてへの参照を保持します。タスクが終了したら、他の2つのタスクも終了しているかどうかを確認します。終了している場合は進行状況ダイアログを閉じ、他のタスクが終了するのを待ってからもう一度確認します。完了したら、必ず参照を解放してください。
  2. 参照を保持したくない場合は、カウンターを保管してください。タスクが終了したら、カウンターをインクリメントし、3に等しいかどうかを確認します。すべてのタスクが終了し、完了した場合。これを実装する場合は、必ずカウンターへのアクセスを同期してください。
23
Mojo Risin

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
 }
7
Jagadeesh

簡単な回避策は、AsyncTaskごとに1つずつ3つのブール変数を使用し、それに応じてそれらをチェックすることです。

より良いアプローチは、AsynTaskを拡張し、onPostExecuteで起動されるコールバックインターフェイスを定義する別のクラスを作成することです。

2
PravinCG

すべてのタスクを保持するフィールドを作成します。

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

}
1
Iraklis

AsyncTaskがいつ終了するか(onPostExecuteが呼び出されるとき)をご存知のとおり:1つの解決策は、カウンターを保持するメソッドsetProgressBarVisible()を作成し、最初にセットを呼び出すことです。表示され、カウンタを減らし、ゼロの場合はプログレスバーを非表示に設定するメソッドsetProgressBarInvisible()

1
MrJre

onPostExecute()で通知するだけです。 onPostExecuteと詳細についてはドキュメントの4つのステップ を参照してください。EventBusを使用してサブスクライブを行うことができます。

0
Olivia Liao

:-?ただのトリックだと思います。各onPostExecuteAsyntaskにメッセージを返し、それを比較します。 (たとえば、このメッセージには時間を含めることができます)

0
hqt

CompletableFuture の公式サポートがAPIレベル24以降に導入されました。

Java 8 here でも利用できます。

次のようなものを使用するだけで使用できます。

taskA.thenCombine(taskB).thenCombine(taskC)
0
superuser

これは、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が機能していない場合は何でもかまいません。

0
Kirill Karmazin