Wait for multiple AsyncTask to complete

前端 未结 5 1023
自闭症患者
自闭症患者 2020-12-15 21:16

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

相关标签:
5条回答
  • 2020-12-15 21:55

    RX Merge operator is your friend.

    Get rid of AsyncTark is slower than RX and you cannot handle Errors

    0 讨论(0)
  • 2020-12-15 21:56

    First, add this class to your project

    public abstract class MultiTaskHandler {
        private int mTasksLeft;
        private boolean mIsCanceled = false;
    
        public MultiTaskHandler(int numOfTasks) {
            mTasksLeft = numOfTasks;
        }
    
        protected abstract void onAllTasksCompleted();
    
        public void taskComplete()  {
            mTasksLeft--;
            if (mTasksLeft==0 && !mIsCanceled) {
                onAllTasksCompleted();
            }
        }
    
        public void reset(int numOfTasks) {
            mTasksLeft = numOfTasks;
            mIsCanceled=false;
        }
    
        public void cancel() {
            mIsCanceled = true;
        }
    }
    

    Then:

    int totalNumOfTasks = 2; //change this to the number of tasks that you are running
    final MultiTaskHandler multiTaskHandler = new MultiTaskHandler(totalNumOfTasks) {
        @Override
        protected void onAllTasksCompleted() {
           //put the code that runs when all the tasks are complete here
        }
    };
    

    Then in each task - when completed, add the line: multiTaskHandler.taskComplete();

    Example:

    (new AsyncTask<Void,Void,Void>() {
    
        @Override
        protected Void doInBackground(Void... voids) {
            // do something...
            return null;
        }
    
        @Override
        protected void onPostExecute(Void aVoid) {
            multiTaskHandler.taskComplete();
        }
    }).execute();
    

    You can use multiTaskHandler.cancel() if you want to cancel the code that runs when all the tasks have completed. For instance - if you have an error (don't forget to also cancel all the other tasks).

    * This solution will not pause the main thread!

    0 讨论(0)
  • 2020-12-15 21:58

    Another Option could be to store all your new threads in an Array.

    Then you could iterate over the Array and wait with thread[i].join for the thread to finish.

    see join() http://developer.android.com/reference/java/lang/Thread.html#Thread(java.lang.Runnable)

    When the Iteration is finished all your threads are done and you can work on

    0 讨论(0)
  • 2020-12-15 22:09

    You should use a CountDownLatch. Here the documentation with examples: java.util.concurrent.CountDownLatch

    Basically you give a reference of CountDownLatch to your threads, and each of them will decrement it when finished:

    countDownLatch.countDown();
    

    The main thread will wait on the termination of all threads using:

    countDownLatch.await();
    
    0 讨论(0)
  • 2020-12-15 22:11

    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"));    
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题