Android AsyncTask límites de los hilos?

Estoy desarrollando una aplicación donde necesito actualizar alguna información cada vez que el usuario inicia sesión en el sistema, también utilizo la base de datos en el teléfono. Para todas esas operaciones (actualizaciones, recuperar datos de db y etc.) utilizo tareas asíncronas. Como hasta ahora no he visto por qué no debería utilizarlos, pero recientemente he experimentado que si hago algunas operaciones algunas de mis tareas asíncronas simplemente dejar de pre-ejecutar y no saltar a doInBackground. Eso era demasiado extraño para dejarlo así, así que desarrollé otra aplicación sencilla sólo para comprobar lo que está mal. Y bastante extraño, consigo el mismo comportamiento cuando la cuenta de tareas asíncronas totales alcanza 5, el 6to uno para en pre-ejecuta.

¿Tiene Android un límite de asyncTasks en Actividad / Aplicación? ¿O es sólo un error y debe ser reportado? ¿Alguien experimentó el mismo problema y tal vez encontró una solución a la misma?

Aquí está el código:

Simplemente cree 5 de esos hilos para trabajar en un fondo:

private class LongAsync extends AsyncTask<String, Void, String> { @Override protected void onPreExecute() { Log.d("TestBug","onPreExecute"); isRunning = true; } @Override protected String doInBackground(String... params) { Log.d("TestBug","doInBackground"); while (isRunning) { } return null; } @Override protected void onPostExecute(String result) { Log.d("TestBug","onPostExecute"); } } 

Y luego crear este hilo. Introducirá preExecute y se bloqueará (no pasará a doInBackground).

 private class TestBug extends AsyncTask<String, Void, String> { @Override protected void onPreExecute() { Log.d("TestBug","onPreExecute"); waiting = new ProgressDialog(TestActivity.this); waiting.setMessage("Loading data"); waiting.setIndeterminate(true); waiting.setCancelable(true); waiting.show(); } @Override protected String doInBackground(String... params) { Log.d("TestBug","doInBackground"); return null; } @Override protected void onPostExecute(String result) { waiting.cancel(); Log.d("TestBug","onPostExecute"); } } 

Todas las AsyncTasks son controladas internamente por un ThreadPoolExecutor (static) compartido y un LinkedBlockingQueue . Cuando llama a execute en un AsyncTask, el ThreadPoolExecutor lo ejecutará cuando esté listo en algún momento en el futuro.

¿Cuándo estoy listo? El comportamiento de un ThreadPoolExecutor está controlado por dos parámetros, el tamaño del conjunto central y el tamaño máximo del conjunto . Si hay menos de los subprocesos del tamaño de la agrupación principal actualmente activos y aparece un nuevo trabajo, el ejecutor creará un nuevo subproceso y lo ejecutará inmediatamente. Si al menos se están ejecutando hilos de tamaño de agrupación central, intentará poner en cola el trabajo y esperar hasta que haya un hilo inactivo disponible (es decir, hasta que se complete otro trabajo). Si no es posible poner en cola el trabajo (la cola puede tener una capacidad máxima), creará un nuevo hilo (hasta el máximo de hilos de tamaño de agrupación) para que los trabajos se ejecuten. Un parámetro keep-alive de tiempo de espera.

Antes de Android 1.6, el tamaño del grupo principal era 1 y el tamaño máximo del grupo era 10. Desde Android 1.6, el tamaño del poro del núcleo es 5 y el tamaño máximo del grupo es 128. El tamaño de la cola es 10 en ambos casos. El tiempo de espera de mantenimiento fue de 10 segundos antes de 2,3, y 1 segundo desde entonces.

Con todo esto en mente, ahora queda claro por qué el AsyncTask sólo aparecerá para ejecutar 5/6 de sus tareas. La sexta tarea se está haciendo cola hasta que se complete una de las otras tareas. Esta es una muy buena razón por la que no debe utilizar AsyncTasks para las operaciones de larga duración – evitará que otras AsyncTasks se ejecuten.

Para completar, si repitió su ejercicio con más de 6 tareas (por ejemplo, 30), verá que más de 6 entrará doInBackground como la cola se doInBackground y el ejecutor se presiona para crear más hilos de trabajo. Si se mantuvo con la tarea de larga duración, debería ver que 20/30 se activa, con 10 todavía en la cola.

@antonyt tiene la respuesta correcta, pero en caso de que usted está buscando una solución simple, entonces usted puede retirar la aguja.

Con él puede definir un tamaño de grupo de hilos personalizado y, a diferencia de AsyncTask , funciona en todas las versiones de Android igual. Con él se puede decir cosas como:

 Needle.onBackgroundThread().withThreadPoolSize(3).execute(new UiRelatedTask<Integer>() { @Override protected Integer doWork() { int result = 1+2; return result; } @Override protected void thenDoUiRelatedWork(Integer result) { mSomeTextView.setText("result: " + result); } }); 

O cosas como

 Needle.onMainThread().execute(new Runnable() { @Override public void run() { // eg change one of the views } }); 

Puede hacer mucho más. Compruébelo en GitHub .

Actualización : Desde la API 19, el tamaño de la agrupación de subprocesos se cambió para reflejar el número de CPUs en el dispositivo, con un mínimo de 2 y un máximo de 4 al inicio, mientras crecía hasta un máximo de CPU .

 // We want at least 2 threads and at most 4 threads in the core pool, // preferring to have 1 less than the CPU count to avoid saturating // the CPU with background work private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; 

También tenga en cuenta que mientras que el ejecutor predeterminado de AsyncTask es serial (ejecuta una tarea a la vez y en el orden en que llegan), con el método

 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) 

Puede proporcionar un Ejecutor para ejecutar sus tareas. Puede proporcionar el THREAD_POOL_EXECUTOR bajo el ejecutor de hood pero sin serialización de tareas, o incluso puede crear su propio Executor y proporcionarlo aquí. Sin embargo, tenga en cuenta cuidadosamente la advertencia en los Javadocs.

Advertencia: Permitir que múltiples tareas se ejecuten en paralelo desde un grupo de subprocesos no es generalmente lo que se desea, porque el orden de su operación no está definido. Por ejemplo, si estas tareas se utilizan para modificar cualquier estado en común (como escribir un archivo debido a un clic de botón), no hay garantías en el orden de las modificaciones. Sin un trabajo cuidadoso es posible en raros casos que la versión más reciente de los datos sea sobrescrita por una más antigua, lo que conduce a problemas oscuros de pérdida de datos y estabilidad. Tales cambios se ejecutan mejor en serie; Para garantizar que dicho trabajo sea serializado independientemente de la versión de la plataforma, puede utilizar esta función con SERIAL_EXECUTOR.

Una cosa más a tener en cuenta es que tanto el framework proporcionado por los ejecutores THREAD_POOL_EXECUTOR como su versión serial SERIAL_EXECUTOR (que es la predeterminada para AsyncTask) son estáticos (construcciones de nivel de clase) y, por lo tanto, compartidos en todas las instancias de AsyncTask en su proceso de aplicación.

  • El procesador de hilos de Android no recibe el mensaje
  • PhoneStateListener en el subproceso de fondo
  • Android verificar el estado WIFI (desconectado o el usuario ha cambiado WIFI) ¿Cómo FLAG?
  • ¿Los BroadcastReceivers de Android comenzaron en un nuevo hilo?
  • La rotación de vista de Android no ocurre después de algunas llamadas de setAnimation
  • Problema con la cámara androide y seguridad de hilo
  • ¿Cuál es la forma correcta de utilizar AudioTrack en modo estático?
  • RxJava Android: cargar datos de caché en los subprocesos adecuados
  • Contexto dentro de un Runnable
  • Reproductor multimedia de Android que provoca mensaje de "hilo muerto"
  • Android: el diseño de inflado toma mucho tiempo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.