uso studio oncancelled implement hilos curso clase asynctask android android-asynctask

studio - implement asynctask android



AsyncTask doInBackground no se ejecuta (7)

Esta pregunta ya tiene una respuesta aquí:

Tengo un problema con la clase AsyncTask. Parece que mi tarea deja de funcionar después de crear 4 o 5 tareas.

Tengo 2 actividades. MainActivity que solo contiene un botón que inicia una segunda actividad llamada ImageActivity.

ImageActivity es muy simple. tiene un onCreate que establece el diseño, y luego inicia una nueva AsyncTask que carga una imagen de internet. Esto funciona bien las primeras veces. Pero de repente deja de funcionar. El método onPreExecute se ejecuta cada vez, pero no el método doInBackground. Intenté simplificar el doInBackground con un bucle para dormir, y ocurre lo mismo. No puedo entender este comportamiento ya que asynctask se cancela y se establece en nulo en el método onDestroy. Así que cada vez que comienzo una nueva ImageActivity, también creo una nueva AsyncTask.

Recreo ImageActivity y la tarea presionando el botón Atrás y luego haciendo clic en el botón en la actividad principal.

¿Alguna idea a alguien? Realmente estoy luchando con este.

ACTUALIZACIÓN: Código que inicia ImageActivity (dentro de un botón en ClickListener)

Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); intent.setClassName(this, ImageActivity.class.getName()); startActivity(intent);

El código anterior inicia esta actividad

public class ImageActivity extends Activity { private AsyncTask<Void, Void, Void> task; public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.main); task = new AsyncTask<Void, Void, Void>() { @Override protected void onPreExecute() { Log.d(TAG, "onPreExecute()"); } @Override protected Void doInBackground(Void... params) { Log.d(TAG, "doInBackground() -- Here is the download"); // downloadBitmap("http://mydomain.com/image.jpg") return null; } @Override protected void onPostExecute(Void res) { Log.d(TAG, "onPostExecute()"); if(isCancelled()){ return; } } }.execute(); } @Override protected void onDestroy() { super.onDestroy(); task.cancel(true); } }

ACTUALIZAR:

He probado utilizando una combinación de Threads tradicional y el método runOnUiThread, y parece funcionar mejor. Ahora el hilo se ejecuta todo el tiempo.


El problema que creo es con la pesada tarea de descarga de imágenes. Incluso si cancela la tarea asíncrona, la descarga de la imagen continuará ejecutándose y la tarea asíncrona no finalizará hasta que se complete la descarga. Es posible que desee comprobar el método isCancelled () en AyncTask mientras se realiza la descarga y anule la descarga si la tarea se cancela.

Como referencia, aquí está la documentación sobre el método cancel (): Intenta cancelar la ejecución de esta tarea. Este intento fallará si la tarea ya se ha completado, ya se ha cancelado o no se puede cancelar por algún otro motivo. Si tiene éxito, y esta tarea no ha comenzado cuando se invoca cancelar, esta tarea nunca debería ejecutarse. Si la tarea ya ha comenzado, el parámetro mayInterruptIfRunning determina si el hilo que ejecuta esta tarea debe interrumpirse para intentar detener la tarea. Llamar a este método dará como resultado que se invoque aCancelado (Objeto) en el subproceso de la interfaz de usuario después de que doInBackground (Objeto []) regrese. Llamar a este método garantiza que onPostExecute (Object) nunca se invoque. Después de invocar este método, debe verificar el valor devuelto por isCancelled () periódicamente desde doInBackground (Object []) para finalizar la tarea lo antes posible.


La eliminación de AsyncTask y el uso de un Thread tradicional en lugar de combinarlo con runOnUiThread parece funcionar. Pero todavía no he encontrado la razón por la cual AsyncTask es tan "inestable".

Aquí está el código que funciona para mí:

public class ImageActivity extends Activity { private Thread worker; public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.main); worker = new Thread(new Runnable(){ private void updateUI(final List<Object> list) { if(worker.isInterrupted()){ return; } runOnUiThread(new Runnable(){ @Override public void run() { // Update view and remove loading spinner etc... } }); } private List<Object> download() { // Simulate download SystemClock.sleep(1000); return new ArrayList<Object>(); } @Override public void run() { Log.d(TAG, "Thread run()"); updateUI(download()); } }); worker.start(); } @Override protected void onDestroy() { super.onDestroy(); worker.interrupt(); } }


Me encontré con este problema también. Si usa AsyncTask.execute , su tarea se ejecuta en una cola en serie (desde la fuente de Android 4.3):

Cuando se introdujo por primera vez, las AsyncTasks se ejecutaron en serie en una única cadena de fondo. Comenzando con DONUT, esto se cambió a un conjunto de subprocesos que permite que varias tareas funcionen en paralelo. Comenzando con HONEYCOMB, las tareas se ejecutan en un único hilo para evitar errores de aplicación comunes causados ​​por la ejecución paralela.

Esto es consistente con el comportamiento que vi. Tuve una AsyncTask apareció un cuadro de diálogo en doInBackground y se bloqueó hasta que se cerró el cuadro de diálogo. El diálogo necesitaba su propia AsyncTask para completarse. El método AsyncTask.doInBackground del diálogo nunca se ejecutó porque la AsyncTask original AsyncTask estaba bloqueada.

La solución es ejecutar el segundo AsyncTask en un Executor separado.



No debe tener que preocuparse por el hilo de limpieza en Android, ya que es administrado por el sistema.

Por favor, también publique el método de descarga de imágenes. ¿Has intentado también no cancelar el hilo en el método onDestroy ()? ¿Cómo devuelve la imagen a su hilo de interfaz de usuario?


Tuve esto también, sin una razón real para no comenzar. Me di cuenta de que después de reiniciar el ADB funcionaba de nuevo. No estoy seguro de por qué es esto, pero funcionó para mí


Use traceview para investigar u obtener un volcado de hilo. Supongo que uno de tus hilos AsyncTask está pendiente de descarga.

AsyncTask tiene un pequeño grupo de subprocesos, por lo que si una de sus tareas se bloquea, podría terminar bloqueando el grupo de subprocesos.

Aquí hay una prueba rápida que puede ejecutar: en 4.3, veo que solo puedo ejecutar 5 subprocesos simultáneos. Cuando sale un hilo, se inician otros hilos.

private void testAsyncTasks() { for (int i = 1; i <= 10; i++) { final int tid = i; new AsyncTask<Integer, Void, Void>() { protected void onPreExecute() { Log.d("ASYNCTASK", "Pre execute for task : " + tid); }; @Override protected Void doInBackground(Integer... args) { int taskid = args[0]; long started = SystemClock.elapsedRealtime(); Log.d("ASYNCTASK", "Executing task: " + taskid + " at " + started); for (int j = 1; j <= 20; j++) { Log.d("ASYNCTASK", " task " + taskid + ", time=" + (SystemClock.elapsedRealtime() - started)); SystemClock.sleep(1000); } return null; } protected void onPostExecute(Void result) { Log.d("ASYNCTASK", "Post execute for task : " + tid); }; }.execute(i); } }