web-dev-qa-db-fra.com

AsyncTask doInBackground ne s'exécute pas

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

J'ai 2 activités. MainActivity qui contient uniquement un bouton qui démarre une deuxième activité appelée ImageActivity.

ImageActivity est très simple. il a un onCreate qui définit la disposition, puis il commence une nouvelle AsyncTask qui charge une image à partir d'Internet. Cela fonctionne bien les premières fois. Mais cela 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 se produit. Je ne peux pas comprendre ce comportement car l'asyncte est annulé et défini sur null dans la méthode onDestroy. Ainsi, chaque fois que je lance une nouvelle ImageActivity, je crée également une nouvelle AsyncTask.

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

Des idées quelqu'un? Je me bats vraiment avec celui-ci.

UPDATE: Code qui démarre 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 ci-dessus commence 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);
    }
}

METTRE À JOUR:

J'ai testé en utilisant une combinaison de threads traditionnels et la méthode runOnUiThread, et cela semble mieux fonctionner. Maintenant, le fil court à chaque fois.

33
Vidar Vestnes

Supprimer la tâche Async et utiliser un traditionnel Thread au lieu de le combiner avec runOnUiThread semble fonctionner. Mais je n'ai toujours pas trouvé la raison pour laquelle la tâche Async 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();
    }
}
23
Vidar Vestnes

J'ai rencontré un problème similaire. Vous ne pouvez pas avoir plusieurs Asynchrones s'exécutant en parallèle jusqu'au SDK 11. Vérifiez ici pour plus d'informations

7
ericwjr

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

Lors de la première introduction, les AsyncTasks étaient exécutées en série sur un seul fichier fil de fond. En commençant par DONUT, cela a été changé en un pool de threads permettant à plusieurs tâches de fonctionner en parallèle. Commençant par HONEYCOMB, les tâches sont exécutées sur un seul thread pour éviter les erreurs courantes erreurs d'application causées par une exécution parallèle.

Ceci est compatible avec le comportement que j'ai vu. J'ai eu un AsyncTask ouvert une boîte de dialogue dans doInBackground et bloqué jusqu'à la fermeture de la boîte de dialogue. Le dialogue avait besoin de sa propre AsyncTask pour se terminer. La méthode AsyncTask.doInBackground de la boîte de dialogue ne s'est jamais exécutée, car la AsyncTask d'origine était toujours bloquée.

La solution consiste à exécuter la deuxième AsyncTask dans une Executor séparée.

6
Heath Borders

Utilisez traceview pour enquêter - ou obtenez un vidage de thread. Je suppose que l’un de vos threads AsyncTask est en attente de téléchargement.

AsyncTask a un petit pool de threads. Par conséquent, si l'une de vos tâches est suspendue, elle risque de bloquer votre pool de threads.

Voici un test rapide que vous pouvez exécuter - sur la version 4.3, je constate que je ne peux exécuter que 5 threads simultanés. Lorsqu'un thread se ferme, 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);

        }
  }
1
DustinB

Je crois que le problème vient de la lourde tâche de téléchargement d’images. Même si vous annulez la tâche async, le téléchargement de l'image continuera à s'exécuter et la tâche ne se terminera pas tant que le téléchargement ne sera pas terminé. Vous souhaiterez peut-être vérifier la méthode isCancelled () sur AyncTask pendant le téléchargement et arrêter 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 ne peut pas être annulée pour une autre raison. En cas de succès et si cette tâche n'a pas démarré lorsque l'annulation est appelée, cette tâche ne doit jamais être exécutée. Si la tâche a déjà commencé, le paramètre mayInterruptIfRunning détermine si le thread qui l'exécute doit être interrompu pour tenter d'arrêter la tâche . L'appel de cette méthode entraînera l'appel de onCancelled (Object) sur le thread d'interface utilisateur après doInBackground (Object []) retourne. L'appel de cette méthode garantit que onPostExecute (Object) n'est jamais appelé. Après avoir appelé cette méthode, vous devez vérifier périodiquement la valeur renvoyée par isCancelled () depuis doInBackground (Object []) pour terminer la tâche le plus tôt possible.

0
habib

Vous ne devriez pas avoir à vous soucier du fil de maintenance dans Android, car il est géré par le système.

S'il vous plaît également poster la méthode de téléchargement d'image. Avez-vous également essayé de ne pas annuler le fil dans la méthode onDestroy ()? Comment retournez-vous l'image dans votre thread d'interface utilisateur?

0
Octavian Damiean

J'avais aussi ça, pas de vraie raison pour ne pas commencer. J'ai remarqué qu'après le redémarrage d'Adb, cela fonctionnait à nouveau. Je ne sais pas pourquoi, mais cela a fonctionné pour moi

0
Alex