Domanda

Sto cercando di eseguire due AsyncTasks allo stesso tempo. (Platform è Android 1.5, HTC Hero.) Tuttavia, solo il primo viene eseguito. Ecco un semplice frammento di per descrivere il mio 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.");
    }
}

L'uscita mi aspetto è il seguente:

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

E così via. Tuttavia, ciò che ottengo è:

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

Il secondo AsyncTask non viene mai eseguito. Se cambio l'ordine delle dichiarazioni execute (), solo il compito foo produrrà in uscita.

Mi sto perdendo qualcosa di ovvio qui e / o fare qualcosa di stupido? Non è possibile eseguire due AsyncTasks allo stesso tempo?

Edit: ho realizzato il telefono in questione corre Android 1.5, ho aggiornato il problema descr. di conseguenza. Io non ho questo problema con un HTC Hero con sistema operativo Android 2.1. Hmmm ...

È stato utile?

Soluzione

AsyncTask utilizza un pool battistrada per l'esecuzione la roba da doInBackground (). La questione è inizialmente (nelle prime versioni del sistema operativo Android) la dimensione della piscina era solo 1, ciò significa che nessun calcoli paralleli per un mazzo di AsyncTasks. Ma in seguito hanno risolto che ora la dimensione è 5, quindi al massimo 5 AsyncTasks possono essere eseguite simultaneamente. Purtroppo non ricordo in quale versione esattamente che hanno cambiato.

UPDATE:

Ecco cosa corrente (2012-01-27) API dice su questo:

  

Quando la prima volta, AsyncTasks sono stati giustiziati in serie su un singolo thread in background. A partire con la ciambella, questo è stato cambiato ad un pool di thread che consentono più attività di operare in parallelo. Dopo HONEYCOMB, si prevede di cambiare questo ad un unico filo per evitare errori dell'applicazione comuni dovuti esecuzione parallela. Se veramente si vuole l'esecuzione parallela, è possibile utilizzare l'executeOnExecutor (esecutore, Params ...) versione di questo metodo con THREAD_POOL_EXECUTOR; tuttavia, si veda il commento lì per le avvertenze sul suo utilizzo.

CIAMBELLA è Android 1.6, Favo è Android 3.0.

UPDATE: 2

Vedere il commento di kabuko da Mar 7 at 1:27.

Si scopre che per le API cui viene utilizzato "un pool di thread consentono più attività di operare in parallelo" (a partire da 1,6 e terminano 3.0) il numero di AsyncTasks esecuzione simultaneamente dipende da quanti esercizi sono stati passati per l'esecuzione già, ma non hanno ancora terminato il loro doInBackground().

Questa è testato / confermata da me su 2.2. Supponiamo di avere un AsyncTask personalizzato che può ospitare solo un secondo in doInBackground(). AsyncTasks utilizzano una coda dimensione fissa internamente per memorizzare compiti ritardati. dimensione della coda è 10 per impostazione predefinita. Se si inizia a 15 le attività personalizzate in fila, poi la prima 5 entrerà loro doInBackground(), ma il resto attenderà in una coda per un thread di lavoro gratuito. Non appena uno dei primi 5 finiture, e quindi rilascia un thread di lavoro, un compito dalla coda inizia l'esecuzione. Quindi in questo caso, al massimo 5 attività verranno eseguite simultaneamente. Tuttavia, se si inizia a 16 le attività personalizzate in fila, poi la prima 5 entrerà loro doInBackground(), il resto 10 otterrà nella coda, ma per il 16 verrà creato un nuovo thread di lavoro in modo che inizierà immediatamente l'esecuzione. Quindi in questo caso, al massimo 6 attività verranno eseguite simultaneamente.

C'è un limite di quanti esercizi possono essere eseguiti contemporaneamente. Dal momento che AsyncTask utilizza un pool esecutore filo con il limitato numero massimo di thread di lavoro (128) e le attività in ritardo di coda ha fissato taglia 10, se si tenta di eseguire più di 138 le attività personalizzate l'applicazione si bloccherà con java.util.concurrent.RejectedExecutionException.

A partire da 3,0 API permette di utilizzare la vostra abitudine pool di thread esecutore tramite il metodo AsyncTask.executeOnExecutor(Executor exec, Params... params). Ciò consente, ad esempio, per configurare le dimensioni dei compiti ritardati coda se predefinito 10 non è quello che ti serve.

Come @Knossos menzioni, v'è la possibilità di utilizzare AsyncTaskCompat.executeParallel(task, params); dalla libreria di supporto v.4 per eseguire compiti in parallelo senza preoccuparsi con livello di API. Questo metodo è diventato deprecato in livello di API 26.0.0.

UPDATE: 3

Ecco una semplice applicazione di test di giocare con il numero di compiti, di serie contro l'esecuzione parallela: https: // GitHub .com / vitkhudenko / test_asynctask

UPDATE: 4 (grazie @penkzhou per la precisazione)

A partire da Android 4.4 si comporta AsyncTask diversamente da quello che è stato descritto in UPDATE: 2 . Ci è un correzione per evitare AsyncTask da creando troppi thread.

Prima di Android 4.4 (API 19) AsyncTask avuto la fcampi opo:

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);

In Android 4.4 (API 19) suddetti settori vengono modificati in questo:

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);

Questa modifica aumenta la dimensione della coda 128 oggetti e riduce il numero massimo di thread al numero di nuclei di CPU * 2 + 1. applicazioni possono ancora presentare lo stesso numero di compiti.

Altri suggerimenti

Questo permette l'esecuzione parallelo su tutte le versioni 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);
}

Questo è un riassunto di risposta eccellente del Arhimed.

Si prega di assicurarsi di utilizzare API di livello 11 o superiore come bersaglio di compilazione del progetto. In Eclipse, che è Project > Properties > Android > Project Build Target. Questo non rompere la compatibilità all'indietro per abbassare i livelli di API. Non ti preoccupare, si otterrà Lint errori se il tuo accidentalmente utilizzo funzionalità introdotte dopo le minSdkVersion. Se davvero si vuole utilizzare le funzionalità introdotte dopo le minSdkVersion, è possibile sopprimere quegli errori usando le annotazioni, ma in tal caso, è necessario prendersi cura di compatibilità voi . Questo è esattamente quello che è successo nel frammento di codice di cui sopra.

Fare suggerimento @sulai più generico:

@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);
}   

Proprio per includere l'ultimo aggiornamento (UPDATE 4) in risposta immacolata @Arhimed s' nel molto buona sintesi di @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);
    }
}

L'Android Developers esempio di bitmap di carico utilizza in modo efficiente un'AsyncTask personalizzato (copiato da Jellybean) in modo da poter utilizzare l'executeOnExecutor in API inferiore a <11

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

Scarica il codice e andare al util pacchetto.

È posible. La mia versione è 4.0.4 dispositivo Android e android.os.Build.VERSION.SDK_INT è 15

Ho 3 filatori

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

E anche io ho una classe Async-Tack.

Ecco il mio codice filatore di carico

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();

Questa è perfettamente funzionante. Ad uno ad uno i miei filatori caricato. Non l'ho fatto executeOnExecutor utente.

Questa è la mia classe Async-task

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();
        }
    }
}

se si desidera eseguire compiti in parallelo, è necessario chiamare il metodo executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name") dopo la versione Android di 3.0; ma questo metodo non è esiste prima di Android 3.0 e 1.6 dopo perché esecuzione parallela di per sé, quindi vi consiglio di personalizzare la propria classe AsyncTask nel progetto, al fine di evitare eccezioni tiro in diversa versione di Android.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top