Estoy tratando de ejecutar dos AsyncTasks al mismo tiempo. (La plataforma es Android 1.5, HTC Hero). Sin embargo, solo se ejecuta el primero. Aquí hay un fragmento simple para describir mi problema:
public class AndroidJunk extends Activity {
class PrinterTask extends AsyncTask<String, Void, Void> {
protected Void doInBackground(String ... x) {
while (true) {
System.out.println(x[0]);
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new PrinterTask().execute("bar bar bar");
new PrinterTask().execute("foo foo foo");
System.out.println("onCreate() is done.");
}
}
El resultado que espero es:
onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo
Y así. Sin embargo, lo que obtengo es:
onCreate() is done.
bar bar bar
bar bar bar
bar bar bar
La segunda AsyncTask nunca se ejecuta. Si cambio el orden de las instrucciones execute (), solo la tarea foo producirá resultados.
¿Me estoy perdiendo algo obvio aquí y / o estoy haciendo algo estúpido? ¿No es posible ejecutar dos AsyncTasks al mismo tiempo?
Editar: me di cuenta de que el teléfono en cuestión ejecuta Android 1.5, actualicé el problema descrito. en consecuencia. No tengo este problema con un HTC Hero con Android 2.1. Hmmm ...
Respuestas:
AsyncTask usa un patrón de grupo de subprocesos para ejecutar el material desde doInBackground (). El problema es inicialmente (en las primeras versiones del sistema operativo Android) el tamaño del grupo era solo 1, lo que significa que no hay cálculos paralelos para un montón de AsyncTasks. Pero luego lo arreglaron y ahora el tamaño es 5, por lo que a lo sumo 5 AsyncTasks pueden ejecutarse simultáneamente. Desafortunadamente no recuerdo en qué versión cambiaron exactamente eso.
ACTUALIZAR:
Esto es lo que la API actual (2012-01-27) dice sobre esto:
DONUT es Android 1.6, HONEYCOMB es Android 3.0.
ACTUALIZACIÓN: 2
Ver el comentario
kabuko
deMar 7 2012 at 1:27
.Resulta que para las API donde se usa "un grupo de subprocesos que permite que múltiples tareas operen en paralelo" (comenzando desde 1.6 y terminando en 3.0), el número de AsyncTasks que se ejecutan simultáneamente depende de cuántas tareas ya se hayan pasado para la ejecución, pero No he terminado su
doInBackground()
todavía.Esto es probado / confirmado por mí en 2.2. Supongamos que tiene una AsyncTask personalizada que solo duerme un segundo
doInBackground()
. AsyncTasks utiliza una cola de tamaño fijo internamente para almacenar tareas retrasadas. El tamaño de la cola es 10 por defecto. Si comienza 15 sus tareas personalizadas en una fila, entonces las primeras 5 ingresarán susdoInBackground()
, pero el resto esperará en una cola para un hilo de trabajo libre. Tan pronto como alguno de los primeros 5 finalice y, por lo tanto, libere un subproceso de trabajo, se iniciará una tarea de la cola. Entonces, en este caso, como máximo 5 tareas se ejecutarán simultáneamente. Sin embargo, si comienza 16 sus tareas personalizadas en una fila, luego las primeras 5 ingresarán a las suyasdoInBackground()
, las 10 restantes entrarán en la cola, pero para el 16 se creará un nuevo subproceso de trabajo para que comience la ejecución de inmediato. Entonces, en este caso, como máximo 6 tareas se ejecutarán simultáneamente.Hay un límite de cuántas tareas se pueden ejecutar simultáneamente. Dado que
AsyncTask
utiliza un ejecutor de grupo de subprocesos con un número máximo limitado de subprocesos de trabajo (128) y la cola de tareas retrasadas tiene un tamaño fijo de 10, si intenta ejecutar más de 138 sus tareas personalizadas, la aplicación se bloquearájava.util.concurrent.RejectedExecutionException
.A partir de 3.0, la API permite utilizar su ejecutor de grupo de subprocesos personalizado a través del
AsyncTask.executeOnExecutor(Executor exec, Params... params)
método. Esto permite, por ejemplo, configurar el tamaño de la cola de tareas retrasadas si el valor predeterminado 10 no es lo que necesita.Como @Knossos menciona, hay una opción para usar
AsyncTaskCompat.executeParallel(task, params);
desde la biblioteca de soporte v.4 para ejecutar tareas en paralelo sin molestarse con el nivel de API. Este método quedó en desuso en el nivel de API 26.0.0.ACTUALIZACIÓN: 3
Aquí hay una aplicación de prueba simple para jugar con varias tareas, ejecución en serie o en paralelo: https://github.com/vitkhudenko/test_asynctask
ACTUALIZACIÓN: 4 (gracias @penkzhou por señalar esto)
A partir de Android 4.4 se
AsyncTask
comporta de manera diferente a lo que se describió en la sección ACTUALIZACIÓN: 2 . Hay una solución para evitarAsyncTask
crear demasiados hilos.Antes de Android 4.4 (API 19)
AsyncTask
tenía los siguientes campos:En Android 4.4 (API 19) los campos anteriores se cambian a esto:
Este cambio aumenta el tamaño de la cola a 128 elementos y reduce la cantidad máxima de subprocesos a la cantidad de núcleos de CPU * 2 + 1. Las aplicaciones aún pueden enviar la misma cantidad de tareas.
fuente
AsyncTaskCompat.executeParallel(task, params);
AsyncTaskCompat.executeParallel(task, params);
que ahora está en desusoEsto permite la ejecución paralela en todas las versiones de Android con API 4+ (Android 1.6+):
Este es un resumen de la excelente respuesta de Arhimed.
Asegúrese de utilizar el nivel de API 11 o superior como objetivo de compilación de su proyecto. En Eclipse, eso es
Project > Properties > Android > Project Build Target
. Esto no interrumpirá la compatibilidad con versiones anteriores para reducir los niveles de API. No se preocupe, recibirá errores de pelusa si usa accidentalmente funciones introducidas más tardeminSdkVersion
. Si realmente desea utilizar las funciones introducidas más tardeminSdkVersion
, puede suprimir esos errores mediante anotaciones, pero en ese caso, debe tener cuidado con la compatibilidad usted mismo . Esto es exactamente lo que sucedió en el fragmento de código anterior.fuente
void startMyTask(AsyncTask<Void, ?, ?> asyncTask)
(si su doInBackground anula)Hacer que la sugerencia de @sulai sea más genérica:
fuente
Solo para incluir la última actualización (ACTUALIZACIÓN 4) en la respuesta inmaculada de @Arhimed en el muy buen resumen de @sulai:
fuente
.executeOnExecutor()
que ahora es redundante para API> = KITKAT, ¿sí?El ejemplo de los desarrolladores de Android de cargar mapas de bits utiliza eficientemente un asinctask personalizado (copiado de jellybean) para que pueda usar executeOnExecutor en apis inferiores a <11
http://developer.android.com/training/displaying-bitmaps/index.html
Descargue el código y vaya al paquete util.
fuente
Es posible. La versión de mi dispositivo Android es 4.0.4 y android.os.Build.VERSION.SDK_INT es 15
Tengo 3 hilanderos
Y también tengo una clase Async-Tack.
Aquí está mi código de carga de la ruleta
Esto está funcionando perfectamente. Uno por uno mis hilanderos cargados. No utilicé executeOnExecutor.
Aquí está mi clase Async-task
fuente
si desea ejecutar tareas paralelas, debe llamar al método
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name")
después de la versión de Android 3.0; pero este método no existe antes de Android 3.0 y después de 1.6 porque se ejecuta en paralelo por sí mismo, así que le sugiero que personalice su propia clase AsyncTask en su proyecto, para evitar lanzar excepciones en diferentes versiones de Android.fuente