Question

Je suis en train d'exécuter deux AsyncTasks en même temps. (Plate-forme est Android 1.5, HTC Hero.) Cependant, seul le premier est exécuté. Voici un extrait simple, pour décrire mon problème:

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 sortie je pense est:

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

Et ainsi de suite. Cependant, ce que je reçois est:

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

La deuxième AsyncTask ne sera exécuté. Si je change l'ordre des execute () déclarations, seule la tâche foo produira une sortie.

Suis-je manque ici quelque chose d'évident et / ou faire quelque chose de stupide? Est-il pas possible d'exécuter deux AsyncTasks en même temps?

Edit: je réalisais le téléphone en question tourne sous Android 1.5, je mis à jour le problème descr. en conséquence. Je n'ai pas ce problème avec un HTC Hero sous Android 2.1. Hmmm ...

Était-ce utile?

La solution

AsyncTask utilise un motif de pool de threads pour l'exécution de la substance à partir de doInBackground (). La question est d'abord (dans les premières versions Android OS) la taille de la piscine était 1, ce qui signifie aucun calcul parallèle pour un tas de AsyncTasks. Mais plus tard, ils ont fixé et maintenant que la taille est 5, donc au plus 5 AsyncTasks peuvent fonctionner simultanément. Malheureusement, je ne me souviens pas exactement de quelle version ils ont changé cela.

Mise à jour:

Voici ce que l'API actuelle (2012-01-27) dit à ce sujet:

  

Lorsque la première, AsyncTasks ont été exécutées en série sur un seul thread d'arrière-plan. A partir de beignet, cela a été changé à un pool de threads permettant de multiples tâches de fonctionner en parallèle. Après HONEYCOMB, il est prévu de changer ce retour à un seul thread pour éviter les erreurs d'application communes causées par l'exécution en parallèle. Si vous voulez vraiment l'exécution en parallèle, vous pouvez utiliser la version executeOnExecutor (Exécuteur, Params ...) de cette méthode avec THREAD_POOL_EXECUTOR; toutefois, voir le commentaire il y a des avertissements sur son utilisation.

DONUT est Android 1.6, 3.0 HONEYCOMB est applications.

UPDATE: 2

Voir le commentaire par kabuko de Mar 7 at 1:27.

Il se trouve que pour les API où « un pool de threads permettant de multiples tâches de fonctionner en parallèle » est utilisé (à partir de 1,6 et se terminant le 3.0) le nombre de cours d'exécution simultanément AsyncTasks dépend du nombre de tâches ont été adoptées pour l'exécution déjà, mais ne l'ont pas encore terminé leur doInBackground().

Ceci est testé / confirmée par moi 2.2. Supposons que vous ayez un AsyncTask personnalisé qui dort juste un deuxième doInBackground(). AsyncTasks utilisent une file d'attente de taille fixe en interne pour stocker des tâches retardées. taille de file d'attente est de 10 par défaut. Si vous commencez à 15 vos tâches personnalisées dans une rangée, puis la première 5 va entrer dans leur doInBackground(), mais le reste attendra dans une file d'attente pour un thread de travail libre. Dès que l'une des 5 premières finitions, et donc libère un thread de travail, une tâche de la file d'attente démarre l'exécution. Donc, dans ce cas, au plus 5 tâches exécutées simultanément. Toutefois, si vous commencez à 16 vos tâches personnalisées dans une rangée, puis la première 5 entrera leur doInBackground(), le reste 10 entrerons dans la file d'attente, mais pour le 16 un nouveau thread de travail sera créé il va commencer immédiatement l'exécution. Donc dans ce cas au plus 6 tâches exécutées simultanément.

Il y a une limite du nombre de tâches peuvent être exécutées simultanément. Étant donné que AsyncTask utilise un exécuteur pool de threads avec nombre maximum limité de threads de travail (128) et la file d'attente des tâches retardées a une taille fixe 10, si vous essayez d'exécuter plus de 138 tâches personnalisées l'application se bloque avec java.util.concurrent.RejectedExecutionException.

A partir de l'API 3.0 permet d'utiliser votre pool de threads via la méthode personnalisée exécuteur testamentaire de AsyncTask.executeOnExecutor(Executor exec, Params... params). Cela permet, par exemple, de configurer la taille de la file d'attente des tâches retardées si par défaut 10 n'est pas ce dont vous avez besoin.

@Knossos mentionne, il y a une possibilité d'utiliser AsyncTaskCompat.executeParallel(task, params); de la bibliothèque de v.4 de support pour exécuter des tâches en parallèle sans se soucier avec le niveau de l'API. Cette méthode est devenue obsolète dans le niveau de l'API 26.0.0.

UPDATE: 3

Voici une application de test simple à jouer avec le nombre de tâches, série par rapport à l'exécution parallèle: https: // github .com / vitkhudenko / test_asynctask

UPDATE: 4 (grâce @penkzhou pour avoir signalé)

A partir de Android 4.4 se comporte de AsyncTask différemment de ce qui a été décrit dans Mise à jour: 2 section . Il est une solution pour éviter AsyncTask de créer trop de threads.

Avant d'Android 4.4 (API 19) AsyncTask a fchamps uite:

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

Dans Android 4.4 (API 19) les champs ci-dessus sont modifiés à ceci:

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

Cette modification augmente la taille de la file d'attente de 128 articles et réduit le nombre maximum de threads au nombre de cœurs de processeurs * 2 + 1. Les applications peuvent toujours présenter le même nombre de tâches.

Autres conseils

Cela permet l'exécution en parallèle sur toutes les versions Android avec 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);
}

Ceci est un résumé d'une excellente réponse Arhimed.

S'il vous plaît assurez-vous d'utiliser le niveau de l'API 11 ou plus comme cible de construction du projet. Dans Eclipse, qui est Project > Properties > Android > Project Build Target. Cette volonté pas briser la compatibilité ascendante à des niveaux inférieurs de l'API. Ne vous inquiétez pas, vous obtiendrez des erreurs Lint si votre utilisation accidentelle fonctionnalités introduites plus tard minSdkVersion. Si vous voulez vraiment utiliser les fonctions introduites au plus tard minSdkVersion, vous pouvez supprimer ces erreurs à l'aide des annotations, mais dans ce cas, vous devez prendre soin de la compatibilité vous . C'est exactement ce qui est arrivé dans l'extrait de code ci-dessus.

Faire suggestion @sulai plus générique:

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

Juste pour inclure la dernière mise à jour (UPDATE 4) réponse immaculée de @Arhimed dans le très bon résumé 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);
    }
}

Les développeurs Android exemple de bitmaps de chargement utilise efficacement un AsyncTask personnalisé (copié à partir Jellybean) afin que vous puissiez utiliser le executeOnExecutor dans apis inférieure à <11

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

Télécharger le code et allez à util package.

Il est posible. My Android version de l'appareil est 4.0.4 et android.os.Build.VERSION.SDK_INT est 15

J'ai 3 filateurs

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

Et aussi j'ai une classe Async-Tack.

Voici mon code de chargement de spinner

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

Cela fonctionne parfaitement. Un par un de mes filateurs chargé. Je ne l'ai pas utilisateur executeOnExecutor.

Voici ma classe Async-tâche

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 vous voulez exécuter des tâches en parallèle, vous devez appeler la méthode executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name") après la version Android 3.0 de; mais cette méthode n'existait pas avant Android 3.0 et après 1,6 parce qu'il exécute en parallèle par lui-même, donc je vous suggère de personnaliser votre propre classe AsyncTask dans votre projet, pour éviter exception lancer dans une version différente Android.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top