web-dev-qa-db-fra.com

Android Bouton Retour et boîte de dialogue de progression

J'ai un AsyncTask qui montre un progressDialog pendant le travail (il appelle runOnUiThread de l'intérieur doInBackground pour afficher la boîte de dialogue de progression).

Pendant son fonctionnement, je souhaite autoriser l'utilisation du bouton de retour pour annuler l'opération; quelqu'un d'autre a eu ce problème: le bouton BACK ne fonctionne pas, alors que progressDialog est en cours d'exécution

Pour quelle raison que ce soit, je ne peux pas répondre à ce fil, donc je dois en commencer un autre?! (Une autre question pour un autre jour)

J'ai eu la même idée que Sandy mais ce code n'est jamais appelé pendant que progressDialog est affiché, pourquoi est-ce? Je l'ai implémenté dans ma classe d'activité principale, le progressDialog éloigne temporairement le focus de premier plan de ma classe?

34
jwbensley

Tout d'abord, vous devez afficher votre boîte de dialogue à partir de OnPreExecute, la masquer dans OnPostExecute et - si nécessaire - la modifier en publiant la progression. (voir ici )

Maintenant à votre question: ProgressDialog.show() peut prendre un OnCancelListener comme argument. Vous devez en fournir un qui appelle cancel() sur l'instance de la boîte de dialogue de progression.

exemple:

    @Override
    protected void onPreExecute(){
        _progressDialog = ProgressDialog.show(
                YourActivity.this,
                "Title",
                "Message",
                true,
                true,
                new DialogInterface.OnCancelListener(){
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        YourTask.this.cancel(true);
                        finish();
                    }
                }
        );
    }

_progressDialog est un membre ProgressDialog de YourTask.

Cette classe est déconseillée au niveau de l'API 26. ProgressDialog est une boîte de dialogue modale qui empêche l'utilisateur d'interagir avec l'application. Au lieu d'utiliser cette classe, vous devez utiliser un indicateur de progression comme ProgressBar, qui peut être intégré dans l'interface utilisateur de votre application. Vous pouvez également utiliser une notification pour informer l'utilisateur de la progression de la tâche. LIEN

45
user634618

Cela peut être réalisé par le fragment de code suivant:

progress.setCancelable(true);
progress.setCanceledOnTouchOutside(false);

progress est l'objet ProgressDialog ...

Cela permettra au bouton de retour de fermer la boîte de dialogue mais empêchera toute saisie tactile de le faire ...

15
Jahid

Eh bien, j'ai eu le même problème. La méthode la plus simple qui a fonctionné pour moi est d'utiliser progressDialog.setCancelable(true) .. Cela déclare si la boîte de dialogue est annulable en appuyant sur la touche Retour. Essayez-le et faites-moi savoir si cela fonctionne pour vous ou non. Bonne chance

13
Farhan

Je viens de trouver une solution parfaite et la plus simple à ce problème. Il existe une méthode dans ProgressDialog pour définir KeyListener.

progressDialog.setOnKeyListener(new OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_BACK && !event.isCanceled()) {
            if(progressDialog.isShowing()) {
                //your logic here for back button pressed event
            } 
            return true;
        }
        return false;
    }
});

Cela fonctionne très bien avec setCancelable(false). Je vérifie également event.isCanceled(), car sans cela, je recevais deux événements. J'ai testé cela sur un appareil Lollipop avec et sans clés matérielles.

9
Ashish Tanna

Traiter le bouton de retour comme une annulation n'est pas la bonne façon.
L'annulation se produit également lorsqu'un utilisateur touche l'écran en dehors de la boîte de dialogue. Vous voulez différencier ces deux actions, non?

L'approche correcte serait d'étendre la classe ProgressDialog et de remplacer la méthode onBackPressed.

private class SubProgressDialog extends ProgressDialog {
    public SubProgressDialog(Context context) {
        super(context);
    }
    @Override
    public void onBackPressed() {
        /** dismiss the progress bar and clean up here **/
    }
}


public void displayProgressBar(){
    progressBar = new SubProgressDialog(this);
    progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    progressBar.setCancelable(false);
    progressBar.setMessage(getString(R.string.authorizing));        
    progressBar.show();   
    new Thread(new Runnable() {
      public void run() {
      }
       }).start();     

}

Notez le setCancelable (false), soulignant à nouveau que le bouton de retour est différent d'une simple annulation.
Cela ignorera également efficacement toute autre entrée tactile de l'utilisateur.

5
Kevin

Voici ma solution à cela. Le problème PD se produit uniquement lorsque l'application se ferme sur le bouton de retour (généralement lorsque l'utilisateur appuie dessus de manière répétitive, et seulement parfois (pas toutes les fois)) PD est appelé lorsque l'application a déjà été détruite. Le fait de rejeter le PD onDestroy ne fonctionne pas pour une raison quelconque et lorsque je l'ai essayé, chaque pression sur le bouton Retour fermerait l'application bien que canGoBack() a été défini sur true. Au lieu de cela, je rejette le PD sur goBack qui est l'événement qui provoque la collision en premier lieu, et je le fais juste avant finish(). Si l'application se ferme normalement sur goBack, il n'y a pas de problème en premier lieu.

BTW, la "différence" vise à permettre à l'utilisateur de quitter l'application avec un double clic rapide (400 MS entre deux clics) au lieu de revenir d'une page à l'autre.

J'espère que cela aide quelqu'un ...

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            difference = System.currentTimeMillis() - startTime;
            if (wView.canGoBack() && difference > 400) {
                wView.goBack();
            } else {
                dismissProgressDialog();
                finish();
            }
            startTime = System.currentTimeMillis();
            return true;
        }
    }
    return super.onKeyDown(keyCode, event);
}


private void dismissProgressDialog() {
   if (progressDialog != null && progressDialog.isShowing()) {
        progressDialog.dismiss();
   }
}
3
ofermc

javano ... J'ai testé votre scénario en utilisant des techniques standard, asyncTask et ProgressDialog. Dans mon test, lorsque le progressDialog s'affiche et que je riposte, le progressdialog est rejeté et le thread d'arrière-plan continue de fonctionner. Je ne sais pas pourquoi vous devez appeler runOnUiThread.

ALORS:

afficher le progressDialog dans onPreExecute placer la tâche de longue durée dans doInBackground ignorer le progressDialog dans onPostExecute passer les paramètres d'entrée à votre longue tâche comme dans:

new MyAsynch().execute(password,inString);

cancel () asynchTask et progressDialog dans onPause

protected void onPause() {
    super.onPause();
    if (asynch != null) {asynch.cancel(true);}
    if (progress != null){progress.cancel();}
}

JAL

J'ai du code ici .

2
JAL

Il est très simple de copier le code ci-dessous et de le coller dans la tâche Async.

Boîte de dialogue ProgressDialog;

@Override
protected void onPreExecute() {

    dialog = new ProgressDialog(MainActivity.this) {
        @Override
        public void onBackPressed() {
            dialog.cancel();
            dialog.dismiss();
        }
    };
    // dialog.setTitle("file is..");//its optional If u want set title in progress
    // bar
    dialog.setMessage("Loading file....");
    dialog.setCancelable(false);

    dialog.show();

}
1

Veuillez suivre ceci, il affiche le bouton d'annulation uniquement en mode asynchrone et terminer sera appelé en cliquant sur le bouton d'annulation

protected void onPreExecute() {


        dialogx.setMessage("Loading... Please Wait...");
        dialogx.setCancelable(false);
        dialogx.setButton(DialogInterface.BUTTON_NEGATIVE,
                "Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

                dialogx.dismiss();
                GetDataTask.this.cancel(true);
                finish();
            }
        });
        dialogx.show();


    }
0
Ahmad Arslan