64 votes

Android - Annuler la tâche asynchrone avec force

J'ai mis en œuvre AsyncTask dans mon un de l'activité:

 performBackgroundTask asyncTask = new performBackgroundTask();
 asyncTask.execute();

Maintenant, j'ai besoin de mettre en œuvre le bouton "Annuler" de la fonctionnalité, donc je dois arrêter l'exécution de la tâche en cours d'exécution. Je ne sais pas comment faire pour arrêter l'exécution de la tâche(tâche de fond).

Merci donc de me suggérer, comment puis-je annuler l'AsyncTask de force ?

Mise à jour:

J'ai trouvé l' Cancel() méthode de la même, mais j'ai trouvé que l'appelant cancel(boolean mayInterruptIfRunning) n'empêche pas nécessairement l'exécution du processus en arrière-plan. Tout ce qui semble se produire est que la AsyncTask exécutera onCancelled(), et ne fonctionne pas onPostExecute() lorsqu'elle est terminée.

90voto

Jacob Nordfalk Points 1505

Il suffit de vérifier isCancelled() temps en temps:

  protected Object doInBackground(Object... x) {
    while (/* condition */) {
      // work...
      if (isCancelled()) break;
    }
    return null;
 }
 

49voto

CommonsWare Points 402670

Appelez cancel() sur le AsyncTask. Si oui ou non ce sera fait, annuler tout est dépendant un peu sur ce que vous faites. Pour citer Romain Guy:

Si vous appelez de l'annuler(vrai), une interruption sera envoyé pour le thread d'arrière-plan, ce qui peut aider à interruptible tâches. Sinon, vous devriez assurez-vous simplement pour vérifier isCancelled() régulièrement votre doInBackground() la méthode. Vous pouvez voir des exemples de ce à code.google.com/p/shelves.

16voto

Yahel Points 5018

Ça dépend vraiment de ce que vous faites sur ce que votre asynctask est en train de faire.

Si c'est une boucle comme lorsque vous traitez un grand nombre de fichiers, vous pouvez simplement vérifier après chaque fichiers si le isCanceled() drapeau est hissé ou pas, puis pause de votre boucle si il est.

Si c'est une ligne de commande qui effectue une très longue opération, il n'y a pas beaucoup que vous pouvez faire.

La meilleure solution serait de ne pas utiliser la méthode d'annulation de l'asynctask et utiliser votre propre cancelFlag booléenne. Vous pouvez ensuite tester cette cancelFlag dans votre postExecute de décider quoi faire avec le résultat.

5voto

elia Points 11

Le mentionné dans les commentaires de cas qu' isCancelled() always returns false even i call asynctask.cancel(true); est particulièrement dangereux si je ferme mon application, mais l'AsyncTask continue de travailler.

Pour résoudre ce j'ai modifié le projet en Jacob Nordfalk code de la façon suivante:

protected Object doInBackground(Object... x) {
    while (/* condition */) {
      // work...
      if (isCancelled() || (FlagCancelled == true)) break;
    }
    return null;
 }

et ajouté ce qui suit à l'activité principale:

@Override
protected void onStop() {
    FlagCancelled = true;
    super.onStop();
}

Comme mon AsyncTask est une classe privée de l'un des points de vue, de sorte que les accesseurs ou compositeurs du drapeau ont été nécessaires pour informer les AsyncTask sur le réel valeur de l'indicateur.

Mes multiples tests (AVD Android 4.2.2, l'Api 17) ont montré que si une AsyncTask est déjà en cours d'exécution de son doInBackground, alors isCancelled() réagit en aucune façon (c'est à dire continue d'être faux) à toute tentative visant à annuler, par exemple lors d' mViewGroup.removeAllViews(); ou au cours d'une OnDestroy de la MainActivity, chaque de ce qui conduit au détachement de vues

   @Override 
   protected  void  onDetachedFromWindow() { 
    mAsyncTask.cancel(false); // and the same result with mAsyncTask.cancel(true);
    super.onDetachedFromWindow(); 
   } 

Si j'arrive à forcer l'arrêt de l' doInBackground() grâce à l'introduction de FlagCancelled, alors onPostExecute() est appelé, mais ni onCancelled() ni onCancelled(Void result) (depuis l'API de niveau 11) ne sont pas invoquées. (Je n'ai aucune idée pourquoi, parce qu'ils doivent être invoquée et onPostExecute() ne devrait pas, "API Android doc a dit:l'Appel de la méthode cancel() garantit que onPostExecute(Objet) n'est jamais appelée." - IdleSun, répondant à une question similaire).

En revanche, si le même AsyncTask n'avais pas commencé son doInBackground() avant d'annuler, alors tout est ok, isCancelled() changements de vrai et je peut vérifier que dans

@Override
    protected void onCancelled() {
        Log.d(TAG, String.format("mAsyncTask - onCancelled: isCancelled = %b, FlagCancelled = %b", this.isCancelled(), FlagCancelled ));
    super.onCancelled();
}

2voto

Droid Chris Points 122

Même si une AsyncTask ne doit pas être utilisé pour de longues opérations, parfois, il peut être pris dans une tâche qui ne répond pas (comme une non-réponse HTTP appel). Dans ce cas, il peut être nécessaire d'annuler l'AsyncTask.

Nous avons à relever des défis dans ce domaine. 1. L'habituelle boîte de dialogue de progression affichée avec une AsyncTask est la première chose annulée sur un AsyncTask lorsque le bouton de retour est pressé par l'utilisateur. 2. L'AsyncTask peut-être dans la méthode doInBackground

Par la création d'un dismissDialogListerner sur le ProgressDialog, un utilisateur peut appuyer sur le bouton de retour et fait annuler le AsycnTask et fermer la boîte de dialogue elle-même.

Voici un exemple:

public void openMainLobbyDoor(String username, String password){
    if(mOpenDoorAsyncTask == null){
        mOpenDoorAsyncTask = (OpenMainDoor) new OpenMainDoor(username, password, Posts.API_URL, 
                mContext, "Please wait while I unlock the front door for you!").execute(null, null, null);
    }
}

private class OpenMainDoor extends AsyncTask<Void, Void, Void>{

    //declare needed variables
    String username, password, url, loadingMessage;
    int userValidated;
    boolean canConfigure;
    Context context;
    ProgressDialog progressDialog;

    public OpenMainDoor(String username, String password, String url, 
                Context context, String loadingMessage){
        userValidated = 0;
        this.username = username;
        this.password = password;
        this.url = url;
        this.context = context;
        this.loadingMessage = loadingMessage;
    }

    /**
     * used to cancel dialog on configuration changes
     * @param canConfigure
     */
    public void canConfigureDialog(boolean canConfigure){
        this.canConfigure = canConfigure;
    }

    @Override
    protected void onPreExecute(){
        progressDialog = new ProgressDialog(this.context);
        progressDialog.setMessage(loadingMessage);
        progressDialog.setIndeterminate(true);
        progressDialog.setCancelable(true);
        progressDialog.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                mOpenDoorAsyncTask.cancel(true);
            }
        });
        progressDialog.show();
        this.canConfigure = true;
    }

    @Override
    protected Void doInBackground(Void... params) {
        userValidated = Posts.authenticateNTLMUserLogin(username, password, url, context);
        while(userValidated == 0){
            if(isCancelled()){
                break;
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void unused){
        //determine if this is still attached to window
        if(canConfigure)
            progressDialog.dismiss();

        if(userValidated == 1){
            saveLoginValues(username, password, true);
            Toast.makeText(context, R.string.main_login_pass, Toast.LENGTH_SHORT).show();
        }else{
            saveLoginValues(username, password, false);
            Toast.makeText(context, R.string.main_login_fail, Toast.LENGTH_SHORT).show();
        }
        nullifyAsyncTask();
    }

    @Override
    protected void onCancelled(){
        Toast.makeText(context, "Open door request cancelled!", Toast.LENGTH_SHORT).show();
        nullifyAsyncTask();
    }
}

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