127 votes

Exécuter AsyncTask plusieurs fois

Dans mon Activité, j'utilise une classe qui s'étend de l'AsyncTask et un paramètre qui est une instance de l'AsyncTask. Quand je l'appelle mInstanceOfAT.execute("") tout va bien. Mais l'application crash quand j'appuie sur un bouton de mise à jour qui appelle de nouveau l'AsyncTask(Dans le cas où le réseau de l'emploi n'a pas fonctionné). Cause apparaît alors une Exception qui dit

Ne peut pas exécuter la tâche: la tâche a déjà exécutée (une tâche peut être exécutée qu'une seule fois)

J'ai essayé d'appeler annuler(true) pour l'instance de la Asyctask, mais il ne marche pas non plus. La seule solution jusqu'à présent, c'est de créer de nouvelles instances de la Asyntask. Est-ce la bonne façon?

Merci.

217voto

Steve Prentice Points 7638

AsyncTask cas ne peut être utilisé qu'une seule fois.

Au lieu de cela, il suffit d'appeler votre tâche comme new MyAsyncTask().execute("");

À partir de l'AsyncTask API docs:

Le filetage des règles

Il y a quelques filetage règles qui doivent être suivies pour cette classe fonctionne correctement:

  • L'instance de la tâche doit être créé sur le thread de l'INTERFACE utilisateur.
  • execute(Params...) doit être appelée sur le thread d'INTERFACE utilisateur.
  • Ne pas appeler onPreExecute(), onPostExecute(Suite), doInBackground(Params...), onProgressUpdate(le Progrès...) manuellement.
  • La tâche peut être exécutée qu'une seule fois (une exception sera levée si une deuxième exécution est tentée.)

28voto

seanhodges Points 8005

Les raisons de l'incendie et d'oublier les instances de ASyncTask sont détaillées assez bien à Steve Prentice réponse - Toutefois, si vous êtes limité sur combien de fois vous exécutez une ASyncTask, vous êtes libre de faire ce que vous aimez, tandis que le fil est en cours d'exécution...

Mettre votre code exécutable à l'intérieur d'une boucle à l'intérieur de doInBackground() et l'utilisation simultanée de verrouillage pour déclencher chaque exécution. Vous pouvez récupérer les résultats à l'aide publishProgress()/onProgressUpdate().

Exemple:

class GetDataFromServerTask extends AsyncTask<Input, Result, Void> {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition tryAgain = lock.newCondition();
    private volatile boolean finished = false;

    @Override
    protected Void doInBackground(Input... params) {

        lock.lockInterruptibly();

        do { 
            // This is the bulk of our task, request the data, and put in "result"
            Result result = ....

            // Return it to the activity thread using publishProgress()
            publishProgress(result);

            // At the end, we acquire a lock that will delay
            // the next execution until runAgain() is called..
            tryAgain.await();

        } while(!finished);

        lock.unlock();
    }

    @Override
    protected void onProgressUpdate(Result... result) 
    {
        // Treat this like onPostExecute(), do something with result

        // This is an example...
        if (result != whatWeWant && userWantsToTryAgain()) {
            runAgain();
        }
    }

    public void runAgain() {
        // Call this to request data from the server again
        tryAgain.signal();
    }

    public void terminateTask() {
        // The task will only finish when we call this method
        finished = true;
        lock.unlock();
    }

    @Override
    protected void onCancelled() {
        // Make sure we clean up if the task is killed
        terminateTask();
    }
}

Bien sûr, c'est un peu plus compliqué que les usages traditionnels de l'ASyncTask, et vous donnent la possibilité d'utiliser la publishProgress() pour les réels rapports sur les progrès réalisés. Mais si la mémoire est votre préoccupation, cette approche permettra d'assurer un seul ASyncTask reste dans le tas au moment de l'exécution.

1voto

Jib Points 981

J'ai fait ma rotation des tâches statiques, ce qui a permis de m'attacher, détacher et rattacher à l'INTERFACE utilisateur de discussions sur la rotation des changements. Mais pour en revenir à votre question, ce que j'ai à faire est de créer un indicateur pour voir si le thread est en cours d'exécution. Lorsque vous voulez relancer le thread, j'ai vérifier si la rotation de la tâche est en cours d'exécution si elle est, je toast un avertissement. Si elle n'est pas, je le fais nulle et puis en créer une nouvelle, qui permettra de contourner l'erreur que vous voyez. En outre, après l'achèvement j'null hors le formulaire de rotation conscients de la tâche, de sorte qu'il est prêt à aller de nouveau.

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