Hasta el 15/2/2012 todavía no he encontrado una buena explicación ni una razón por la que esto no funciona. Lo más cercano a una solución es usar el enfoque tradicional de Thread , pero entonces, ¿por qué incluir una clase que no (parece) funcionar en el SDK de Android?
¡Incluso así!
Tengo una subclase AsyncTask:
// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener
Eso se ejecuta así:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
Ahora bien, esta subclase se ha encontrado con un pequeño error. Anteriormente, hizo un análisis de xml, pero cuando noté que no se llamaba doInBackground () , lo eliminé , línea por línea, y finalmente terminé con esto:
@Override
protected Void doInBackground(String... params)
{
Log.v(TAG, "doInBackground");
return null;
}
Que, por alguna razón, no registró nada. Sin embargo, agregué esto:
@Override
protected void onPreExecute()
{
Log.v(TAG, "onPreExecute");
super.onPreExecute();
}
Y esa línea de hecho se registra al ejecutar el hilo. Entonces, de alguna manera, se llama a onPreExecute () pero no a doInBackground () . Tengo otra AsyncTask ejecutándose en segundo plano al mismo tiempo que funciona bien.
Actualmente estoy ejecutando la aplicación en un emulador, SDK versión 15, Eclipse, Mac OS X 10.7.2, cerca del Polo Norte.
EDITAR:
@Override
protected void onProgressUpdate(RSSItem... values) {
if(values[0] == null)
{
// activity function which merely creates a dialog
showInputError();
}
else
{
Log.v(TAG, "adding "+values[0].toString());
_tableManager.addRSSItem(values[0]);
}
super.onProgressUpdate(values);
}
_tableManager.addRSSItem () más o menos agrega una fila a una SQLiteDatabase, inicializada con el contexto de la actividad. publishProgress () es llamado por la devolución de llamada de Interface ParseListener. Sin embargo, dado que ni siquiera hago nada excepto log.v en doInBackground (), primero encontré esto innecesario incluso para abrirlo.
EDITAR 2:
Muy bien, para que quede perfectamente claro, esta es la otra AsyncTask, ejecutándose en la misma actividad y funcionando perfectamente bien.
private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
Integer prevCount;
boolean run;
@Override
protected void onPreExecute() {
run = true;
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
run = true;
prevCount = 0;
while(run)
{
ArrayList<RSSItem> items = _tableManager.getAllItems();
if(items != null)
{
if(items.size() > prevCount)
{
Log.v("db Thread", "Found new item(s)!");
prevCount = items.size();
RSSItem[] itemsArray = new RSSItem[items.size()];
publishProgress(items.toArray(itemsArray));
}
}
SystemClock.sleep(5000);
}
return null;
}
@Override
protected void onProgressUpdate(RSSItem... values) {
ArrayList<RSSItem> list = new ArrayList<RSSItem>();
for(int i = 0; i < values.length; i++)
{
list.add(i, values[i]);
}
setItemsAndUpdateList(list);
super.onProgressUpdate(values);
}
@Override
protected void onCancelled() {
run = false;
super.onCancelled();
}
}
EDITAR 3:
Suspiro, lo siento, soy malo haciendo preguntas. Pero aquí está la inicialización de las tareas.
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.execute("http://www.nothing.com", null);
}
Respuestas:
La solución de Matthieu funcionará bien para la mayoría, pero algunos pueden enfrentar problemas; a menos que busque en muchos enlaces proporcionados aquí o desde la web, como la explicación de Anders Göransson . Estoy tratando de resumir algunas otras lecturas aquí y explicar rápidamente la solución si executeOnExecutor todavía está funcionando en un solo hilo ...
El comportamiento de
AsyncTask().execute();
ha cambiado a través de las versiones de Android. Antes de Donut (Android: 1.6 API: 4) las tareas se ejecutaban en serie, desde Donut hasta Gingerbread (Android: 2.3 API: 9) las tareas se ejecutaban en paralelo; desde que la ejecución de Honeycomb (Android: 3.0 API: 11) se cambió de nuevo a secuencial;AsyncTask().executeOnExecutor(Executor)
sin embargo, se agregó un nuevo método para la ejecución en paralelo.En el procesamiento secuencial, todas las tareas Async se ejecutan en un solo hilo y, por lo tanto, deben esperar antes de que finalice la tarea anterior. Si necesita ejecutar código inmediatamente, necesita que las tareas se procesen en paralelo en subprocesos separados.
Con AsyncTask, la ejecución en serie no está disponible entre las versiones de Donut y Honeycomb, mientras que la ejecución en paralelo no está disponible antes de Donut.
Para el procesamiento paralelo después de Donut: verifique la versión de compilación y, en base a eso, use el método .execute () o .executeOnExecutor (). El siguiente código puede ayudar ...
NOTE:
La función.executeOnExecutor()
comprueba si eltargetSdkVersion
proyecto es menor o igual aHONEYCOMB_MR1
(Android: 2.1 API: 7) y luego obliga al ejecutor a serloTHREAD_POOL_EXECUTOR
(que ejecuta Tareas secuencialmente en la publicación Honeycomb).Si no ha definido un
targetSdkVersion
,minSdkVersion
se considera automáticamente que es eltargetSdkVersion
.Por lo tanto, para ejecutar su AsyncTask en paralelo en la publicación Honeycomb, no puede dejarlo
targetSdkVersion
vacío.fuente
Debe consultar esta respuesta: https://stackoverflow.com/a/10406894/347565 y el enlace a los grupos de Google que incluye.
Tuve un problema similar al tuyo, todavía no está claro por qué no funciona, pero cambié mi código de esta manera y el problema desapareció:
fuente
Puede hacer esto de dos maneras:
Camino 1 :
En caso de que la forma 1 no funcione, pruebe la forma 2 .
Camino 2 :
Espero que esto te ayudará.
fuente
Tuve el mismo problema: no se puede ejecutar una segunda AsyncTask después de que llamé a "ejecutar" en la primera: solo se llama a doInBackground para la primera.
Para responder por qué sucede esto, marque esta respuesta (comportamiento diferente según el SDK)
Sin embargo, para su caso, este obstáculo se puede evitar usando executeOnExecutor (disponible a partir de 3.0 funcionó para mí usando 4.0.3) pero tenga cuidado con las limitaciones del tamaño del grupo de subprocesos y la cola.
¿Puedes probar algo como esto?
Para su pregunta de actualización: se explica en los documentos Básicamente solo para evitar todos los problemas que pueden provenir de subprocesos múltiples como interferencia ...
fuente
Una cosa que me gustaría saber, y que en realidad podría solucionar su problema, es ¿dónde está creando una instancia de su clase y llamando al método execute ()? Si lee la documentación de AsyncTask, ambas operaciones deben tener lugar en el hilo principal de la IU. Si está creando su objeto y llamando a ejecutar desde algún otro hilo, entonces onPreExecute podría dispararse, no estoy 100% seguro aquí, pero el hilo de fondo no se creará ni ejecutará.
Si está creando la instancia de su AsyncTask desde un subproceso en segundo plano, o alguna otra operación que no se lleva a cabo en el subproceso principal de la interfaz de usuario, podría considerar usar el método: Activity.runOnUiThread (Runnable)
Necesitaría acceder a una instancia de su Actividad en ejecución para llamar a ese método, pero le permitirá ejecutar código en el subproceso de la IU desde algún otro código que no se esté ejecutando en el subproceso de la IU.
Espero que tenga sentido. Hágame saber si puedo ayudar más.
David
fuente
¡Android es brutal! No puedo creer esto, qué implementación tan simple que cambia de un día para otro. Un día es un solo hilo, al siguiente es 5 y el otro es 128.
De todos modos, aquí hay un reemplazo cercano a la caída de la acción AsyncTask. Incluso puede llamarlo AsyncTask si lo desea, pero para evitar confusiones se llama ThreadedAsyncTask. Debe llamar a executeStart () en lugar de ejecutar porque execute () es final.
fuente
Sé que esto puede ser muy tarde para el hilo, pero hay una razón por la que no funcionará en los emuladores de Android posteriores. Cuando se introdujo asynctask, Android solo le permitió ejecutar una a la vez, luego, en algún momento, no estoy seguro de qué versión, le permitieron ejecutar múltiples asynctasks a la vez, esto causó problemas en muchas aplicaciones, por lo que en Honeycomb + volvieron a solo permitiendo que se ejecute un asynctask a la vez. A menos que cambie manualmente el grupo de subprocesos. Espero que aclare una o dos cosas para la gente.
fuente
Creo que es el SDK. Tuve el mismo problema, y después de cambiar el SDK de destino de 15 a 11, todo funciona perfectamente.
con sdk15, aunque AsyncTask.Status está EN EJECUCIÓN, nunca se llama a doInBackground. Aunque creo que tiene algo que ver con el hilo de la interfaz de usuario.
fuente
Según la respuesta de Matthieu, debajo de una clase de ayuda para ejecutar su
AsyncTask
correctamente dependiendo de la versión del SDK para evitar duplicar el código en su aplicación:Ejemplo de uso:
...
fuente