Pregunta

Estoy tratando de ejecutar dos AsyncTasks al mismo tiempo. (Plataforma es Android 1.5, HTC Hero.) Sin embargo, sólo la primera se ejecuta. He aquí un fragmento simple de 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.");
    }
}

La salida que espero es:

onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo

Y así sucesivamente. Sin embargo, lo que consigo es:

onCreate() is done.
bar bar bar
bar bar bar
bar bar bar

El segundo AsyncTask nunca se ejecutó. Si cambio el orden de las instrucciones execute (), sólo la tarea foo producirá una salida.

Me estoy perdiendo algo obvio aquí y / o hacer algo estúpido? No es posible ejecutar dos AsyncTasks al mismo tiempo?

Edit: me di cuenta de que el teléfono en cuestión corre Android 1.5, he actualizado la descr problema. en consecuencia. No tengo este problema con un héroe de HTC con Android 2.1. Hmmm ...

¿Fue útil?

Solución

AsyncTask utiliza un patrón de agrupación de hebras para el funcionamiento de las cosas de doInBackground (). La cuestión es inicialmente (en las primeras versiones de Android OS) el tamaño de la piscina era sólo 1, es decir, no hay cálculos paralelos para un grupo de AsyncTasks. Pero más tarde se fijan eso y ahora el tamaño es 5, por lo que en la mayoría de 5 AsyncTasks se pueden ejecutar simultáneamente. Por desgracia, no recuerdo exactamente en qué versión cambiaron eso.

ACTUALIZACIÓN:

Esto es lo actual (2012-01-27) API dice sobre esto:

  

Cuando introdujo por primera vez, AsyncTasks fueron ejecutados en serie en un solo hilo de fondo. Comenzando con el buñuelo, esto fue cambiado a un grupo de subprocesos múltiples tareas que permiten operar en paralelo. Después de HONEYCOMB, está previsto para cambiar esto de nuevo a un solo hilo para evitar errores de aplicación comunes causadas por la ejecución en paralelo. Si realmente desea la ejecución en paralelo, se puede utilizar el executeOnExecutor (Ejecutor, Parámetros ...) versión de este método con THREAD_POOL_EXECUTOR; Sin embargo, véase el comentario allí por las advertencias sobre su uso.

buñuelo es Android 1.6, Android 3.0 de nido de abeja.

UPDATE: 2

Ver el comentario por kabuko de Mar 7 at 1:27.

Resulta que para las API donde se utiliza "un grupo de subprocesos que permiten múltiples tareas operen en paralelo" (a partir de 1,6 y que terminan en 3.0) el número de AsyncTasks se ejecutan simultáneamente depende de cuántas tareas se han aprobado para su ejecución ya, pero no han terminado su doInBackground() todavía.

Esto se prueba / confirmado por mí en 2.2. Suponga que tiene un AsyncTask personalizado que solo duerme en una segunda doInBackground(). AsyncTasks utilizan una cola de tamaño fijo internamente para almacenar las tareas de retraso. tamaño de la cola es de 10 por defecto. Si usted comienza a 15 sus tareas personalizadas en una fila, a continuación, en primer lugar 5 entrará en su doInBackground(), pero el resto va a esperar en una cola para un subproceso de trabajo libre. Tan pronto como cualquiera de los 5 primeros acabados, y por lo tanto libera un subproceso de trabajo, una tarea de la cola se iniciará la ejecución. Por lo tanto en este caso como máximo 5 tareas se ejecutarán simultáneamente. Sin embargo si se inicia 16 sus tareas personalizadas en una fila, a continuación, en primer lugar 5 entrará en su doInBackground(), el resto 10 se meterá en la cola, pero para el día 16, se creará un nuevo subproceso de trabajo por lo que va a empezar la ejecución inmediatamente. Por lo tanto 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. Desde AsyncTask utiliza un grupo ejecutor hilo con limitado número máximo de subprocesos de trabajo (128) y las tareas retardadas cola ha fijado el tamaño de 10, si se intenta ejecutar más de 138 tareas personalizados la aplicación se bloquea con java.util.concurrent.RejectedExecutionException.

A partir de la API 3.0 permite utilizar su costumbre grupo de subprocesos ejecutor a través del método AsyncTask.executeOnExecutor(Executor exec, Params... params). Esto permite, por ejemplo, para configurar el tamaño de las tareas retardadas cola si por defecto 10 no es lo que necesita.

Como @Knossos menciones, hay una opción para el uso de la biblioteca de soporte AsyncTaskCompat.executeParallel(task, params); v.4 para ejecutar tareas en paralelo sin molestarse con el nivel de API. Este método se ha hecho obsoleto en el nivel de la API 26.0.0.

UPDATE: 3

Esta es una aplicación de prueba simple para jugar con el número de tareas, frente a la ejecución en paralelo de serie: https: // github .com / vitkhudenko / test_asynctask

ACTUALIZACIÓN: 4 (gracias @penkzhou por señalar esto)

A partir de Android 4.4 se comporta AsyncTask diferente a lo que se describe en ACTUALIZACIÓN: 2 . Hay es una solución para evitar AsyncTask de crear demasiados hilos.

Antes de Android 4.4 (API 19) AsyncTask tenía la fespués de campos:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

En Android 4.4 (API 19) los campos anteriores se cambian a esto:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

Este cambio aumenta el tamaño de la cola de 128 artículos y reduce el número máximo de hilos que el número de núcleos de CPU * 2 + 1. Aplicaciones todavía se puede presentar el mismo número de tareas.

Otros consejos

Esto permite la ejecución en paralelo en todas las versiones de Android con API 4+ (Android 1.6 +):

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}

Este es un resumen de la excelente respuesta de Arhimed.

Por favor asegúrese de usar API de nivel 11 o superior como su destino de generación del proyecto. En Eclipse, es decir Project > Properties > Android > Project Build Target. Esta voluntad no romper la compatibilidad hacia atrás para reducir los niveles de API. no se preocupe, se producirán errores Lint si su uso accidental características introducidas más tarde de minSdkVersion. Si realmente desea utilizar las características incorporadas a más tardar minSdkVersion, puede suprimir esos errores utilizando anotaciones, pero en ese caso, es necesario tener cuidado acerca de la compatibilidad mismo . Esto es exactamente lo que sucedió en el fragmento de código de seguridad.

Hacer sugerencia @sulai más genérico:

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}   

Sólo para incluir la última actualización (Update 4) en respuesta inmaculada @Arhimed 's en el muy buen resumen de @sulai:

void doTheTask(AsyncTask task) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Android 4.4 (API 19) and above
        // Parallel AsyncTasks are possible, with the thread-pool size dependent on device
        // hardware
        task.execute(params);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Android 3.0 to
        // Android 4.3
        // Parallel AsyncTasks are not possible unless using executeOnExecutor
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    } else { // Below Android 3.0
        // Parallel AsyncTasks are possible, with fixed thread-pool size
        task.execute(params);
    }
}

El desarrolladores ejemplo androide de mapas de bits de carga utiliza eficientemente un AsyncTask personalizado (copiado de gominola) para que pueda utilizar el executeOnExecutor en apis más baja que <11

http://developer.android.com/training/displaying-bitmaps/ index.html

Descargar el código e ir a util paquete.

Es posible. Mi versión dispositivo Android 4.0.4 y es android.os.Build.VERSION.SDK_INT es 15

Tengo 3 hiladores

Spinner c_fruit=(Spinner) findViewById(R.id.fruits);
Spinner c_vegetable=(Spinner) findViewById(R.id.vegetables);
Spinner c_beverage=(Spinner) findViewById(R.id.beverages);

Y también tengo una clase asíncrono-Tack.

Aquí está mi código spinner carga

RequestSend reqs_fruit = new RequestSend(this);
reqs_fruit.where="Get_fruit_List";
reqs_fruit.title="Loading fruit";
reqs_fruit.execute();

RequestSend reqs_vegetable = new RequestSend(this);
reqs_vegetable.where="Get_vegetable_List";
reqs_vegetable.title="Loading vegetable";
reqs_vegetable.execute();

RequestSend reqs_beverage = new RequestSend(this);
reqs_beverage.where="Get_beverage_List";
reqs_beverage.title="Loading beverage";
reqs_beverage.execute();

Esto está funcionando perfectamente. Uno por uno mis hiladores cargado. No lo hice executeOnExecutor usuario.

Esta es mi clase asíncrono-tarea

public class RequestSend  extends AsyncTask<String, String, String > {

    private ProgressDialog dialog = null;
    public Spinner spin;
    public String where;
    public String title;
    Context con;
    Activity activity;      
    String[] items;

    public RequestSend(Context activityContext) {
        con = activityContext;
        dialog = new ProgressDialog(activityContext);
        this.activity = activityContext;
    }

    @Override
    protected void onPostExecute(String result) {
        try {
            ArrayAdapter<String> adapter = new ArrayAdapter<String> (activity, android.R.layout.simple_spinner_item, items);       
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spin.setAdapter(adapter);
        } catch (NullPointerException e) {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        } catch (Exception e)  {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
        super.onPostExecute(result);

        if (dialog != null)
            dialog.dismiss();   
    }

    protected void onPreExecute() {
        super.onPreExecute();
        dialog.setTitle(title);
        dialog.setMessage("Wait...");
        dialog.setCancelable(false); 
        dialog.show();
    }

    @Override
    protected String doInBackground(String... Strings) {
        try {
            Send_Request();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        return null;
    }

    public void Send_Request() throws JSONException {

        try {
            String DataSendingTo = "http://www.example.com/AppRequest/" + where;
            //HttpClient
            HttpClient httpClient = new DefaultHttpClient();
            //Post header
            HttpPost httpPost = new HttpPost(DataSendingTo);
            //Adding data
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);

            nameValuePairs.add(new BasicNameValuePair("authorized","001"));

            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            // execute HTTP post request
            HttpResponse response = httpClient.execute(httpPost);

            BufferedReader reader;
            try {
                reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuilder builder = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    builder.append(line) ;
                }

                JSONTokener tokener = new JSONTokener(builder.toString());
                JSONArray finalResult = new JSONArray(tokener);
                items = new String[finalResult.length()]; 
                // looping through All details and store in public String array
                for(int i = 0; i < finalResult.length(); i++) {
                    JSONObject c = finalResult.getJSONObject(i);
                    items[i]=c.getString("data_name");
                }

            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

si desea ejecutar tareas en paralelo, es necesario llamar al método executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name") después de la versión de Android de 3,0; pero este método no es existir antes de Android 3.0 y 1.6 después de ejecutar en paralelo, ya que por sí mismo, lo que sugiero permite personalizar su propia clase AsyncTask en su proyecto, para evitar excepción tiro en diferentes versiones de Android.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top