267 votes

Exécuter plusieurs AsyncTasks en même temps - pas possible?

Je suis en train de lancer deux AsyncTasks en même temps. (Plateforme Android 1.5, HTC Hero.) Toutefois, seul le premier est exécuté. Voici un extrait de 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 j'attends:

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 n'est jamais exécutée. Si je change l'ordre de l'exécuter() relevés, seuls les foo tâche de produire une sortie.

Ai-je raté quelque chose d'évident ici et/ou de faire quelque chose de stupide? Il n'est pas possible de faire fonctionner deux AsyncTasks en même temps?

Edit: j'ai réalisé que le téléphone en question tourne sous Android 1.5, j'ai 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 ...

442voto

Arhimed Points 18116

AsyncTask utilise un pool de threads modèle pour l'exécution de la substance à partir de doInBackground(). La question est à l'origine (en début de versions OS Android) la taille du pool est à seulement 1, ce qui signifie pas de calculs en parallèle pour un tas de AsyncTasks. Mais plus tard, ils ont résolu et maintenant la taille est de 5, donc au plus 5 AsyncTasks peuvent s'exécuter simultanément. Malheureusement, je ne me souviens pas en quelle version exactement ils ont changé ça.

Mise à JOUR:

Voici ce courant (2012-01-27) API dit à ce sujet:

Lors de sa première apparition, AsyncTasks ont été exécutés en série sur un seul thread d'arrière-plan. En commençant par DONUT, cela a été changé pour un pool de threads qui permet de réaliser plusieurs tâches en parallèle. Après en NID d'abeille, il est prévu de le changer vers un seul thread pour éviter les erreurs d'application causés par l'exécution en parallèle. Si vous voulez vraiment de l'exécution en parallèle, vous pouvez utiliser le executeOnExecutor(Exécuteur testamentaire, Params...) version de cette méthode avec THREAD_POOL_EXECUTOR; cependant, voir le commentaire là pour en garde sur son utilisation.

DONUT est Android 1.6, en NID d'abeille est Android 3.0.

Mise à JOUR: 2

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

Il s'avère que pour les Api, où "un pool de threads qui permet de réaliser plusieurs tâches en parallèle" est utilisé (à partir de 1.6 et se terminant 3.0) le numéro de l'exécution simultanée de AsyncTasks dépend comment beaucoup de tâches ont été transmis pour exécution déjà, mais n'ont pas terminé leur doInBackground() encore.

C'est testé et/ou confirmées par moi sur 2.2. Supposons que vous avez une coutume AsyncTask qui dort juste une seconde, en doInBackground(). AsyncTasks fixe la taille de la file d'attente à l'interne pour le stockage de retard de tâches. 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 5 premières vont entrer dans leur doInBackground(), mais le reste va attendre dans une file d'attente pour un travailleur libre du fil. Dès les 5 premières finitions, et donc libère un thread de travail, une tâche de la file d'attente va lancer l'exécution. Donc dans ce cas dans la plupart des 5 tâches s'exécutent simultanément. Toutefois, si vous commencez à 16 vos tâches personnalisées dans une rangée, puis 5 premières vont entrer dans leur doInBackground(), le reste 10 se met dans la file d'attente, mais pour le 16e un nouveau thread de travail sera créé afin d'en lancer l'exécution voit tout de suite. Donc dans ce cas dans la plupart des 6 tâches s'exécutent simultanément.

Il y a une limite de nombre de tâches peuvent être exécutées simultanément. Depuis AsyncTask utilise un pool de threads exécuteur testamentaire limité le nombre maximum de threads de travail (128) et le retard dans les tâches de la file d'attente de taille fixe 10, si vous essayez d'exécuter plus de 138 personnalisée des tâches de l'application tombe en panne en java.util.concurrent.RejectedExecutionException.

Départ depuis la version 3.0 de l'API permet d'utiliser votre personnalisée pool de threads exécuteur via AsyncTask.executeOnExecutor(Executor exec, Params... params) méthode. Cela permet, par exemple, pour configurer la taille du fait du retard dans les tâches de la file d'attente si le défaut de 10 n'est pas ce dont vous avez besoin.

Mise à JOUR: 3

Voici un test simple application pour jouer avec le nombre de tâches, de série contre l'exécution en parallèle: https://github.com/vitkhudenko/test_asynctask

Mise à JOUR: 4 (merci @penkzhou pour le signaler)

À partir de Android 4.4 AsyncTask se comporte différemment de ce qui a été décrit dans la mise à JOUR: 2 section. Il est un correctif pour empêcher AsyncTask de la création d'un trop grand nombre de threads.

Avant d'Android 4.4 (API 19) AsyncTask a les champs suivants:

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:

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

Ce changement augmente la taille de la file d'attente à 128 éléments et réduit le nombre maximal de threads pour le nombre de cœurs du PROCESSEUR * 2 + 1. Les applications peuvent encore présenter le même nombre de tâches.

222voto

sulai Points 1264

Cela permet l'exécution en parallèle sur toutes les versions d'android avec l'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é de Arhimed excellente réponse.

Assurez-vous d'utiliser l'API de niveau 11 ou plus que votre projet de construction de la cible. Dans Eclipse, c'est - Project > Properties > Android > Project Build Target. Cela permettra de ne pas casser la compatibilité descendante à la baisse des API niveaux. Ne vous inquiétez pas, vous obtiendrez les Peluches des erreurs si votre accidentellement utiliser les fonctionnalités introduites au plus tard minSdkVersion. Si vous voulez vraiment utiliser les fonctionnalités introduites au plus tard minSdkVersion, vous pouvez supprimer ces erreurs à l'aide d'annotations, mais dans ce cas, vous devez prendre soin au sujet de la compatibilité de vous-même. C'est exactement ce qui s'est passé dans l'extrait de code ci-dessus.

21voto

AsafK Points 256

Suggestion de @sulai rendant plus générique :

4voto

OriolJ Points 677

L’exemple de développeurs android de chargement efficacement les bitmaps utilise une asynctask personnalisée (copié à partir de jellybean) donc vous pouvez utiliser l’executeOnExecutor en API inférieur à 11

http://developer.Android.com/Training/Displaying-bitmaps/index.html

Télécharger le code et allez dans le paquet util.

3voto

Il est posible. Ma version de l’appareil android est 4.0.4 et android.os.Build.VERSION.SDK_INT 15

J’ai 3 fileuses

Et j’ai également une classe Async-Tack.

Voici mon spinner charger ce code

Cela fonctionne parfaitement. Un chargement de mon spinners. Je n’ai pas executeOnExecutor de l’utilisateur.

Voici ma classe Async-tâche

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X