Execute AsyncTask several times
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.)
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.
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.