Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute AsyncTask several times

People also ask

How many times an instance of AsyncTask can be executed?

AsyncTask instances can only be used one time.

What happen if we call execute more than once in AsyncTask?

Limitation Of AsyncTask There is a limit of how many tasks can be run simultaneously. Since AsyncTask uses a thread pool executor with max number of worker threads (128) and the delayed tasks queue has fixed size 10. If you try to execute more than 138 AsyncTasks the app will crash with java.

Why did AsyncTask get deprecated?

This class was deprecated in API level 30. AsyncTask was intended to enable proper and easy use of the UI thread. However, the most common use case was for integrating into UI, and that would cause Context leaks, missed callbacks, or crashes on configuration changes.

What is the replacement of AsyncTask?

Alternative 1: Using Executor and Handler The executor will help in performing any task in the background and the handler will help to make UI changes.


AsyncTask instances can only be used one time.

Instead, just call your task like new MyAsyncTask().execute("");

From the AsyncTask API docs:

Threading rules

There are a few threading rules that must be followed for this class to work properly:

  • The task instance must be created on the UI thread.
  • execute(Params...) must be invoked on the UI thread.
  • Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
  • The task can be executed only once (an exception will be thrown if a second execution is attempted.)

The reasons for fire-and-forget instances of ASyncTask are detailed pretty well in Steve Prentice's answer - However, whilst you are restricted on how many times you execute an ASyncTask, you are free to do what you like whilst the thread is running...

Put your executable code inside a loop within doInBackground() and use a concurrent lock to trigger each execution. You can retrieve the results using publishProgress()/onProgressUpdate().

Example:

class GetDataFromServerTask extends AsyncTask<Input, Result, Void> {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition tryAgain = lock.newCondition();
    private volatile boolean finished = false;

    @Override
    protected Void doInBackground(Input... params) {

        lock.lockInterruptibly();

        do { 
            // This is the bulk of our task, request the data, and put in "result"
            Result result = ....

            // Return it to the activity thread using publishProgress()
            publishProgress(result);

            // At the end, we acquire a lock that will delay
            // the next execution until runAgain() is called..
            tryAgain.await();

        } while(!finished);

        lock.unlock();
    }

    @Override
    protected void onProgressUpdate(Result... result) 
    {
        // Treat this like onPostExecute(), do something with result

        // This is an example...
        if (result != whatWeWant && userWantsToTryAgain()) {
            runAgain();
        }
    }

    public void runAgain() {
        // Call this to request data from the server again
        tryAgain.signal();
    }

    public void terminateTask() {
        // The task will only finish when we call this method
        finished = true;
        lock.unlock();
    }

    @Override
    protected void onCancelled() {
        // Make sure we clean up if the task is killed
        terminateTask();
    }
}

Of course, this is slightly more complicated than the traditional usage of ASyncTask, and you give up the use of publishProgress() for actual progress reporting. But if memory is your concern, then this approach will ensure only one ASyncTask remains in the heap at runtime.


I had the same issue. In my case i have a task i want to do in onCreate() and in onResume(). So i made my Asynctask static, and get the instance from it. Now we still have the same problem.

So what i did in the onPostExecute() is this:

instance = null;

Keeping in mind that i check in the static getInstance method that my instance isn't null, else i create it:

if (instance == null){
    instance = new Task();
}
return instance;

The method in postExecute will empty the instance and recreate it. Of course this can be done outside the class.


I have made my rotation tasks static, which then helped me attach, detach, and reattach them to UI threads on rotation changes. But to go back to your question, what I do is create a flag to see if the thread is running. When you want to restart the thread I check if the rotation task is running if it is I toast a warning. If it is not, I make it null and then create a new one, which will work around the error you are seeing. Furthermore, upon successful completion I null out the completed rotation aware task so that it is ready to go again.