Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for multiple AsyncTask to complete

I am parallelizing my operation by splitting it in the exact number of cores available and then, by start the same number of AsyncTask, performing the same operation but on different portions of data.

I am using executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ...) in order to parallelize the execution of them.

I would like to know when every thread finishes its job so that combine all results and perform further operations.

How can I do?

like image 900
Nicholas Allio Avatar asked Sep 17 '15 08:09

Nicholas Allio


People also ask

Can we run multiple async task at a time?

executeOnExecutor(AsyncTask. THREAD_POOL_EXECUTOR); So in order to execute multiple AsyncTask in parallel, we have to use THREAD_POOL_EXECUTOR and execute the AsyncTasks.

How many times an instance of AsyncTask can be executed?

AsyncTask instances can only be used one time.

Can an AsyncTask be executed in a worker thread?

Just for the Record: If you start a AsyncTask outside the UI-Thread the onPreExecute will not be executed from the UI-Thread (but from the caller Thread). This will lead to an exception. However the onPostExecute Method will always be executed on the UI-Thread.

Is it possible to start AsyncTask from background thread?

To start an AsyncTask the following snippet must be present in the MainActivity class : MyTask myTask = new MyTask(); myTask. execute(); In the above snippet we've used a sample classname that extends AsyncTask and execute method is used to start the background thread.


1 Answers

You could also simply decrement a counter in a shared object as part of onPostExecute. As onPostExecute runs on the same thread (the main thread), you won't have to worry about synchronization.

UPDATE 1

The shared object could look something like this:

public class WorkCounter {
    private int runningTasks;
    private final Context ctx;

    public WorkCounter(int numberOfTasks, Context ctx) {
        this.runningTasks = numberOfTasks;
        this.ctx = ctx;
    }
    // Only call this in onPostExecute! (or add synchronized to method declaration)
    public void taskFinished() {
        if (--runningTasks == 0) {
            LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this.ctx);
            mgr.sendBroadcast(new Intent("all_tasks_have_finished"));
        }
    }
}

UPDATE 2

According to the comments for this answer, OP is looking for a solution in which he can avoid building a new class. This can be done by sharing an AtomicInteger among the spawned AsyncTasks:

// TODO Update type params according to your needs.
public class MyAsyncTask extends AsyncTask<Void,Void,Void> {
    // This instance should be created before creating your async tasks.
    // Its start count should be equal to the number of async tasks that you will spawn.
    // It is important that the same AtomicInteger is supplied to all the spawned async tasks such that they share the same work counter.
    private final AtomicInteger workCounter;

    public MyAsyncTask(AtomicInteger workCounter) {
        this.workCounter = workCounter;
    }

    // TODO implement doInBackground

    @Override
    public void onPostExecute(Void result) {
        // Job is done, decrement the work counter.
        int tasksLeft = this.workCounter.decrementAndGet();
        // If the count has reached zero, all async tasks have finished.
        if (tasksLeft == 0) {
            // Make activity aware by sending a broadcast.
            LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this.ctx);
            mgr.sendBroadcast(new Intent("all_tasks_have_finished"));    
        }
    }
}
like image 82
Janus Varmarken Avatar answered Sep 19 '22 03:09

Janus Varmarken