2010-11-02 6 views
32

J'ai un problème avec la classe AsyncTask. Il semble que ma tâche cesse de fonctionner après avoir créé 4 ou 5 tâches.AsyncTask doInBackground ne s'exécute pas

Im ayant 2 activités. MainActivity qui ne contient qu'un bouton qui lance une seconde activité appelée ImageActivity.

ImageActivity est très simple. il a un onCreate qui définit la mise en page, puis il démarre une nouvelle asyncTask qui charge une image à partir d'Internet. Cela fonctionne bien les premières fois. Mais que ça cesse soudainement de fonctionner. La méthode onPreExecute est exécutée à chaque fois, mais pas la méthode doInBackground. J'ai essayé de simplifier le doInBackground avec une boucle de sommeil, et la même chose arrive. Je ne peux pas comprendre ce comportement puisque l'asynctask est à la fois annulé et mis à null dans la méthode onDestroy. Donc, chaque fois que je lance une nouvelle ImageActivity, je crée aussi une nouvelle AsyncTask.

Je recréer l'ImageActivity et la tâche en appuyant sur le bouton Précédent, puis en cliquant sur le bouton MainActivity.

Vous avez des idées? Je me bats vraiment avec celui-ci.

MISE À JOUR: Le code qui commence le ImageActivity (dans un bouton onClickListener)

Intent intent = new Intent(); 
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 
intent.setClassName(this, ImageActivity.class.getName()); 
startActivity(intent); 

Le code commence au-dessus de cette activité

public class ImageActivity extends Activity { 

    private AsyncTask<Void, Void, Void> task; 

    public void onCreate(Bundle bundle) { 
     super.onCreate(bundle); 
     setContentView(R.layout.main); 

     task = new AsyncTask<Void, Void, Void>() { 

      @Override 
      protected void onPreExecute() 
      { 
       Log.d(TAG, "onPreExecute()"); 
      } 

      @Override 
      protected Void doInBackground(Void... params) 
      { 
       Log.d(TAG, "doInBackground() -- Here is the download"); 
       // downloadBitmap("http://mydomain.com/image.jpg") 
       return null; 
      } 

      @Override 
      protected void onPostExecute(Void res) 
      { 
       Log.d(TAG, "onPostExecute()"); 
       if(isCancelled()){ 
        return; 
       } 
      } 
     }.execute(); 
    } 

    @Override 
    protected void onDestroy() 
    { 
     super.onDestroy(); 
     task.cancel(true); 
    } 
} 

MISE À JOUR:

Je l'ai testé en utilisant une combinaison de Threads traditionnels et la méthode runOnUiThread, et il semble fonctionner mieux. Maintenant, le thread s'exécute à chaque fois.

+0

Postez votre code. Comment l'appelez-vous. Nous n'avons aucune idée de comment vous aider sans code – Falmarri

+0

Ayant exactement le même problème, après avoir démarré plusieurs AsyncTasks dans mon application, l'application ne s'exécute que jusqu'à onPreExecute(), mais ne saisit pas doInBackground(). Essayer votre approche Thread maintenant .. –

+1

Je rencontre le même problème. La chose étrange est que cela varie d'un appareil à l'autre. Il se produit sur une tablette (Android 4.0), mais un téléphone (Android 2.3.4) exécutant exactement le même code ne l'a pas. – Hong

Répondre

22

Retrait de la AsyncTask et en utilisant un fil traditionnel au lieu de le combiner avec runOnUiThread semble fonctionner. Mais je n'ai toujours pas trouvé la raison pour laquelle AsyncTask est si "instable".

Voici le code qui fonctionne pour moi:

public class ImageActivity extends Activity { 

    private Thread worker; 

    public void onCreate(Bundle bundle) { 
     super.onCreate(bundle); 
     setContentView(R.layout.main); 

     worker = new Thread(new Runnable(){ 

      private void updateUI(final List<Object> list) 
      { 
       if(worker.isInterrupted()){ 
        return; 
       } 
       runOnUiThread(new Runnable(){ 

        @Override 
        public void run() 
        { 
         // Update view and remove loading spinner etc... 
        } 
       }); 
      } 

      private List<Object> download() 
      { 
       // Simulate download 
       SystemClock.sleep(1000); 
       return new ArrayList<Object>(); 
      } 

      @Override 
      public void run() 
      { 
       Log.d(TAG, "Thread run()"); 
       updateUI(download()); 
      } 

     }); 
     worker.start(); } 

    @Override 
    protected void onDestroy() 
    { 
     super.onDestroy(); 
     worker.interrupt(); 
    } 
} 
+1

Merci, j'ai le même problème (posté ici sur SO un peu tout en arrière et il n'a pas résolu le problème) une recherche Google m'a amené ici :) – Ryan

+5

Cela explique pourquoi AsyncTask peut vous avoir échoué (et moi!): http://foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html – Archie1986

+0

Juste en partageant une pensée, j'ai récemment rencontré quelque chose de vaudou comme le comportement de 'AsyncTask'. Cependant, je l'ai dépassée après avoir fermé en arrière-plan un 'AsyncTask 'déjà lancé. Bizarre, mais ça a marché pour moi. – faizanjehangir

0

Vous ne devriez pas avoir à vous inquiéter de thread d'entretien ménager dans Android car il est géré par le système.

Veuillez également poster la méthode de téléchargement d'image. Avez-vous également essayé de ne pas annuler le thread dans la méthode onDestroy()? Comment renvoyez-vous l'image à votre thread d'interface utilisateur?

+0

La méthode downloadBitmap est un peu longue, et ce n'est pas le problème. J'obtiens le même problème si j'essaye Thread.sleep (5000) simulant un téléchargement lent. Quand j'utilise le Thread.sleep, je peux démarrer l'ImageActivity 3-4 fois et la tâche fonctionne. Après cela, la tâche imprime uniquement onPreExecute et non le message de journal "doInBackground", ce qui signifie qu'elle n'est jamais appelée pour une raison quelconque. Et oui, j'ai essayé de ne pas annuler la tâche, mais je n'ai pas aidé. –

+0

Y a-t-il plus de code que vous avez omis? –

0

Le problème que je crois est la tâche de téléchargement d'image lourde. Même si vous annulez la tâche asynchrone, le téléchargement de l'image continuera à s'exécuter et la tâche asynchrone ne se terminera pas tant que le téléchargement ne sera pas terminé. Vous voudrez peut-être vérifier la méthode isCancelled() sur AyncTask pendant le téléchargement et tuer le téléchargement si la tâche est annulée. Pour référence, voici la documentation sur la méthode cancel(): Tente d'annuler l'exécution de cette tâche. Cette tentative échouera si la tâche est déjà terminée, a déjà été annulée ou n'a pas pu être annulée pour une autre raison. En cas de succès, et que cette tâche n'a pas démarré lorsque cancel est appelée, cette tâche ne devrait jamais être exécutée. Si la tâche a déjà démarré, le paramètre mayInterruptIfRunning détermine si le thread exécutant cette tâche doit être interrompu pour tenter d'arrêter la tâche. L'appel de cette méthode entraîne l'invocation de onCancelled (Object) sur le thread de l'interface utilisateur après le retour de doInBackground (Object []). L'appel de cette méthode garantit que onPostExecute (Object) n'est jamais appelé. Après avoir invoqué cette méthode, vous devez vérifier périodiquement la valeur renvoyée par isCancelled() à partir de doInBackground (Object []) pour terminer la tâche le plus tôt possible.

1

Utilisez traceview pour rechercher - ou obtenir un vidage de thread. Ma conjecture est que l'un de vos threads AsyncTask sont suspendus lors du téléchargement. AsyncTask a un petit pool de threads, donc si une de vos tâches se bloque, cela pourrait bloquer votre pool de threads.

Voici un test rapide que vous pouvez exécuter - sur 4.3, je vois que je n'ai que 5 threads simultanés que je peux exécuter. Quand un thread se termine, d'autres threads démarrent.

private void testAsyncTasks() { 

     for (int i = 1; i <= 10; i++) { 
       final int tid = i; 
       new AsyncTask<Integer, Void, Void>() { 
        protected void onPreExecute() { 
          Log.d("ASYNCTASK", "Pre execute for task : " + tid); 
        }; 

        @Override 
        protected Void doInBackground(Integer... args) { 
          int taskid = args[0]; 
          long started = SystemClock.elapsedRealtime(); 
          Log.d("ASYNCTASK", "Executing task: " + taskid + " at " + started); 
          for (int j = 1; j <= 20; j++) { 
           Log.d("ASYNCTASK", " task " + taskid + ", time=" + (SystemClock.elapsedRealtime() - started)); 
           SystemClock.sleep(1000); 
          } 
          return null; 
        } 

        protected void onPostExecute(Void result) { 
          Log.d("ASYNCTASK", "Post execute for task : " + tid); 
        }; 
       }.execute(i); 

     } 
    } 
7

J'ai rencontré un problème similaire. Vous ne pouvez pas avoir plusieurs Asynctasks fonctionnant en parallèle jusqu'à ce que le SDK 11. Vérifiez here for more info

0

Je l'avais aussi, pas de véritable raison de ne pas démarrer. J'ai remarqué qu'après avoir redémarré adb, cela a fonctionné à nouveau. Je ne sais pas pourquoi c'est, mais cela a fonctionné pour moi

5

Je viens de rencontrer ce problème. Si vous utilisez AsyncTask.execute, votre tâche est exécutée sur une file d'attente de série (à partir de la source de 4.3 Android):

Lorsque la première, 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é en un pool de threads permettant à plusieurs tâches de fonctionner en parallèle. À partir de HONEYCOMB, les tâches sont exécutées sur un seul thread afin d'éviter les erreurs d'application courantes provoquées par l'exécution parallèle.

Ceci est cohérent avec le comportement que j'ai vu. J'ai eu un AsyncTask surgi un dialogue dans doInBackground et bloqué jusqu'à ce que la boîte de dialogue a été fermée. Le dialogue avait besoin de son propre AsyncTask pour terminer. La méthode AsyncTask.doInBackground du dialogue n'a jamais été exécutée car le AsyncTask d'origine était toujours bloqué.

La solution consiste à exécuter le second AsyncTask dans un Executor distinct.

+0

doInBackground() ne devrait pas appeler les méthodes UI (par exemple pour faire apparaître une boîte de dialogue comme vous l'avez mentionné). –

+0

J'ai montré le dialogue sur le thread principal, mais il a été déclenché par 'doInBackground'. –

+1

C'est la bonne réponse qui devrait être acceptée. (Je viens de terminer ma propre enquête sur le sujet et suis arrivé à la même conclusion - Executor séparé) –

Questions connexes