Ejecute AsyncTask varias veces

En mi actividad utilizo una clase que se extiende desde AsyncTask y un parámetro que es una instancia de esa AsyncTask. Cuando llamo a mInstanceOfAT.execute("") todo está bien. Pero la aplicación falla cuando presiono un botón de actualización que llama nuevamente a AsyncTask (en caso de que el trabajo de red no haya funcionado). Porque entonces aparece una excepción que dice

No se puede ejecutar la tarea: la tarea ya se ha ejecutado (una tarea se puede ejecutar solo una vez)

He intentado llamar a cancelar (verdadero) para la instancia de Asyctask, pero tampoco funciona. La única solución hasta ahora es crear nuevas instancias del Asyntask. ¿Es esa la forma correcta?

Gracias.

AsyncTask instancias de AsyncTask solo se pueden usar una vez.

En su lugar, simplemente llame a su tarea como new MyAsyncTask().execute("");

De los documentos de la API AsyncTask:

Enhebrar las reglas

Hay algunas reglas de enhebrado que se deben seguir para que esta clase funcione correctamente:

  • La instancia de la tarea debe crearse en el hilo de la interfaz de usuario.
  • execute (Params …) debe invocarse en el subproceso UI.
  • No invoque onPreExecute (), onPostExecute (Result), doInBackground (Params …), onProgressUpdate (Progress …) manualmente.
  • La tarea se puede ejecutar solo una vez (se lanzará una excepción si se intenta una segunda ejecución).

Los motivos de las instancias de “apagar y olvidar” de ASyncTask se detallan bastante bien en la respuesta de Steve Prentice. Sin embargo, aunque se restringe la cantidad de veces que ejecuta un ASyncTask, puede hacer lo que quiera mientras se ejecuta el subproceso. .

Coloque su código ejecutable dentro de un bucle dentro de doInBackground () y use un locking concurrente para activar cada ejecución. Puede recuperar los resultados utilizando publishProgress () / onProgressUpdate () .

Ejemplo:

 class GetDataFromServerTask extends AsyncTask { 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(); } } 

Por supuesto, esto es un poco más complicado que el uso tradicional de ASyncTask, y usted renuncia al uso de publishProgress () para el informe de progreso real. Pero si la memoria es su preocupación, este enfoque garantizará que solo una ASyncTask permanezca en el montón en tiempo de ejecución.

He hecho que mis tareas de rotación estén estáticas, lo que me ayudó a conectarlas, separarlas y volver a conectarlas a los subprocesos de la interfaz de usuario en los cambios de rotación. Pero para volver a su pregunta, lo que hago es crear una bandera para ver si el hilo se está ejecutando. Cuando quiera reiniciar el hilo, verifico si la tarea de rotación se está ejecutando si es que brindo una advertencia. Si no es así, lo hago nulo y luego creo uno nuevo, lo que funcionará alrededor del error que está viendo. Además, al completar con éxito anulo la tarea completa de rotación consciente para que esté lista para continuar.

Tuve el mismo problema. En mi caso, tengo una tarea que quiero hacer en onCreate() y en onResume( ). Así que hice mi Asynctask estática y obtuve la instancia de ella. Ahora todavía tenemos el mismo problema.

Entonces, lo que hice en onPostExecute () es esto:

 instance = null; 

Teniendo en cuenta que verifico en el método estático getInstance que mi instancia no es nula, de lo contrario la creo:

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

El método en postExecute vaciará la instancia y la volverá a crear. Por supuesto, esto se puede hacer fuera de la clase.

Sí, es cierto, el doc dice que solo se puede ejecutar un Asyntask.

Cada vez que necesite usarlo, tiene que instanciar:

 // Any time if you need to call her final FirmwareDownload fDownload = new FirmwareDownload(); fDownload.execute("your parameter"); static class FirmwareDownload extends AsyncTask { }