73 votes

Dialogues / AlertDialogs : Comment "bloquer l'exécution" pendant que la boîte de dialogue est ouverte (.NET-style)

Venant de l'environnement .NET, je cherche maintenant à comprendre comment les dialogues fonctionnent dans Android.

Dans .NET, lorsque l'on appelle MessageBox.Show(...) qui crée et affiche une boîte de dialogue contextuelle. Dans l'appel à Show, je peux spécifier les boutons qui doivent être disponibles dans la fenêtre pop-up, par exemple :

DialogResult myDialogResult = MessageBox.Show("My text here", "My caption here", MessageBoxButtons.YesNoCancel);

Comme vous pouvez le voir, l'appel à Show renvoie un DialogResult lorsqu'un bouton est pressé dans la fenêtre contextuelle, m'informant ainsi du bouton qui a été cliqué. Notez que dans .NET, l'exécution est arrêtée à la ligne où l'appel à Show(...) est faite, afin qu'elle puisse renvoyer la valeur lorsqu'un bouton est pressé.

Si, dans l'exemple ci-dessus, j'appuie sur "Non", myDialogResult sera égal à

myDialogResult == DialogResult.No

Étant donné que je trouve la méthode .NET d'utilisation et de création des fenêtres contextuelles très facile et intuitive, j'aimerais que cette méthode de création des fenêtres contextuelles soit également utilisée dans Android.

Donc, la question est de savoir si quelqu'un sait comment "arrêter l'exécution" comme avec la fonction MessageBox.Show puis retourner une valeur lorsque le bouton est pressé (et que la boîte de dialogue disparaît) ?

Edit 1

Pour être un peu plus clair :

J'ai besoin que l'exécution s'arrête et attende que l'utilisateur ait choisi un bouton à cliquer dans la popup. Le code qui suit l'appel pour afficher la fenêtre de dialogue dépend du bouton cliqué dans la fenêtre de dialogue.

C'est pourquoi je ne peux pas utiliser ce que Erich et Alex suggèrent, car écrire du code dans les méthodes onClick comme suggéré ci-dessous ne va pas fonctionner. La raison en est que je ne peux pas poursuivre l'"exécution normale". Prenons un exemple :

Laissez-moi prendre un exemple :

int nextStep = 0; // this variable will not be reached from within the onClick-methods

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Hello!")
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                nextStep = 1; // *** COMPILER ERROR!! ***
            }
        })
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                nextStep = 2; // *** COMPILER ERROR!! ***
            }
        })
        .create().show();

if (nextStep == 1)
{
    // then do some damage
}
else if (nextStep == 2
    // dont do damage

Si je voulais que l'exécution dépende du choix dans la fenêtre popup, je devrais faire en sorte que toutes les variables de l'"exécution normale" (dans le cas présent nextStep ) disponibles dans les méthodes onClick, et ça me semble être l'enfer.

Edit 2

Un autre exemple évident serait une fenêtre pop-up demandant "Voulez-vous continuer" avec les options "Oui" et "Non" .

Si l'utilisateur appuie sur "Oui", toute la méthode doit être interrompue, sinon elle doit poursuivre son exécution. Comment résoudre ce problème ?

0 votes

Voir si le paragraphe ajouté par fupsduck aide

4 votes

Vous pouvez également concevoir votre "dialogue" comme une activité ayant le même aspect et la même convivialité qu'un dialogue. Si votre dialogue comporte beaucoup de logique, il pourrait être plus facile à mettre en œuvre de cette façon.

3 votes

En ce qui concerne la boîte de dialogue d'alerte, .NET est génial, et Android est nul. Dans certains cas, j'ai besoin de MessageBox pour faciliter le débogage. Dans .NET, le code qui suit la MessageBox ne s'exécute pas tant que vous n'avez pas fermé la MessageBox. Cependant, dans Android, cela ne fonctionne pas. Je pense que dans Windows, il y a une autre boucle de messages lors de l'affichage d'une boîte de dialogue modale. Dans Android, je pense que la fenêtre et le dialogue utilisent la même boucle de message.

49voto

Romain Guy Points 57114

Ted, vous ne voulez pas faire ça, vraiment :) La principale raison est que si vous bloquez le thread de l'interface utilisateur pendant que vous affichez une boîte de dialogue, vous bloquez le thread chargé de dessiner et de gérer les événements de votre boîte de dialogue. Ce qui signifie que votre dialogue ne répondra pas. Vous provoquerez également des ANR si l'utilisateur met plus de quelques secondes à cliquer sur la boîte de dialogue.

La réponse d'Erich est exactement ce dont vous avez besoin. Je sais que ce n'est pas ce que vous veulent mais cela n'a pas d'importance. Nous avons conçu Android pour empêcher les développeurs d'écrire des boîtes de dialogue synchrones, de sorte que vous n'avez pas vraiment le choix.

0 votes

Hé Romain, merci pour la réponse. J'ai trouvé ce fil où un type avait le même problème. Bien sûr, je n'ai pas le choix, j'en suis sûr.

1 votes

J'ai écrit des applications où plusieurs dialogues modaux sont présentés les uns après les autres. L'utilisateur doit répondre à tous ces dialogues avant de poursuivre. Par exemple, il y a un certain nombre de "questions de contrôle" auxquelles l'utilisateur doit répondre avant de poursuivre. Disons que nous avons 3 questions de ce type - ce serait un désordre complet à créer dans Android tel que je le comprends. Nous avons besoin d'un tas de méthodes plutôt inutiles, une pour chaque boîte de dialogue que nous présentons à l'utilisateur. Le code est "charcuté" et divisé, difficile à suivre et désordonné en général. C'est vraiment dommage, je pense =( (note : j'aime Android par d'autres aspects)

20 votes

C'est un désordre car vous architecturez votre code d'une manière qui n'est pas prévue pour Android. Faites-le simplement différemment . Si vous refusez de le faire, c'est votre problème. Par exemple, au lieu d'utiliser 3 dialogues de blocage (ce que je trouve être une interface terrible et paresseuse d'ailleurs), pourquoi ne pas avoir une activité qui pose toutes les questions et seulement quand l'utilisateur valide vous commencez à faire ce que votre application est censée faire. Vous avez posé une question, nous y avons répondu et jusqu'à présent la seule chose que vous avez dite est que vous n'aimez pas nos réponses. Désolé, mais elles ne changeront pas.

22voto

Erich Douglass Points 21714

Dans Android, la structure est différente de celle de .NET :

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Hello!")
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // Handle Ok
           }
       })
       .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // Handle Cancel
           }
       })
       .create();

Vous obtiendrez une boîte de dialogue avec deux boutons et vous gérerez les clics de bouton avec des callbacks. Il est possible d'écrire du code pour que la syntaxe soit plus proche de celle de .NET, mais le cycle de vie de la boîte de dialogue est assez étroitement lié à la technologie Activity donc à la fin, ça pourrait être plus de problèmes que ça n'en vaut la peine. Les autres références de dialogue sont ici .

8 votes

Donc il n'y a pas de dialogue "modal" dans Android ? Vous n'êtes pas sérieux.

20voto

MindSpiker Points 575

Une version simplifiée de la réponse de Daniel ci-dessus. Cette fonction obtient un oui ou un non de l'utilisateur dans une boîte de dialogue d'alerte, mais elle pourrait facilement être modifiée pour obtenir d'autres entrées.

private boolean mResult;
public boolean getYesNoWithExecutionStop(String title, String message, Context context) {
    // make a handler that throws a runtime exception when a message is received
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message mesg) {
            throw new RuntimeException();
        } 
    };

    // make a text input dialog and show it
    AlertDialog.Builder alert = new AlertDialog.Builder(context);
    alert.setTitle(title);
    alert.setMessage(message);
    alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mResult = true;
            handler.sendMessage(handler.obtainMessage());
        }
    });
    alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mResult = false;
            handler.sendMessage(handler.obtainMessage());
        }
    });
    alert.show();

    // loop till a runtime exception is triggered.
    try { Looper.loop(); }
    catch(RuntimeException e2) {}

    return mResult;
}

0 votes

Merci, celui-ci fonctionne bien. Je préfère la méthode d'Erich mais elle ne bloque pas l'exécution (la solution que j'utilise souvent). Au moins, votre méthode fonctionne comme prévu par la question et la réponse est intéressante.

0 votes

C'est la réponse la plus proche de la question et c'est une solution créative. Mais elle échoue parfois avec une erreur fatale comme celle-ci : A/libc Fatal signal 11 (SIGSEGV), code 1, fault addr 0x1 in tid 274... Quelqu'un a-t-il trouvé une solution à ce problème ?

0 votes

Je voudrais dire que cela fonctionne aussi pour les requêtes HTTP. Je viens de faire une requête HTTP via Volley, qui a cette idée que le code doit continuer (dans la menace principale) tout en faisant la requête HTTP. Grand service, cependant, pourquoi ne pas nous laisser décider en tant que programmeurs, si oui ou non nous voulons nous asseoir et faire de la gymnastique avec un niveau de profondeur d'appel sans fin, ou faire notre propre threading si oui ? Votre excellent exemple ci-dessus a fonctionné sans qu'une seule vis ou un seul écrou ne soit ajouté. Et maintenant, j'ai des appels HTTP modaux J'ai cependant résolu le cas de l'AlertDialog via un threading normal ( !). Où peut-on partager avec le reste d'entre vous

12voto

Dave Webb Points 90034

Dans Android, les boîtes de dialogue sont asynchrones. Vous allez donc devoir structurer votre code un peu différemment.

Donc, en C#, votre logique se déroulait comme ceci en pseudocode :

void doSomeStuff() {
    int result = showDialog("Pick Yes or No");

    if (result == YES) {
        //do stuff for yes
    }
    else if (result == NO) {
        //do stuff for no
    }

    //finish off here
}

Pour Android, il faudra que ce soit moins soigné. Pensez-y de la manière suivante. Vous aurez un OnClickListener comme ça :

public void onClick(DialogInterface dialog, int whichButton) {
   if (whichButton == BUTTON_POSITIVE) {
      doOptionYes();
   }
   else if (whichButton == BUTTON_NEGATIVE) {
      doOptionNo();
   }
}

Ce qui est ensuite soutenu par les méthodes suivantes :

void doOptionYes() {
    //do stuff for yes
    endThings();
}

void doOptionNo() {
    //do stuff for no
    endThings();
}

void endThings() {
    //clean up here
}

Ainsi, ce qui était une méthode en est maintenant quatre. Cela peut sembler moins net, mais c'est ainsi que cela fonctionne, j'en ai peur.

1 votes

Merci Dave ! Oui, c'est ce que j'ai appris de toutes ces réponses. Malheureusement, je dois dire... Merci encore =)

3 votes

Je trouve cela un peu frustrant parce que parfois mon flux d'exécution contourne le dialogue si tout est ok. s'il y a un problème je demande "continuez" ou "oubliez-le". donc maintenant j'ai 2 façons d'obtenir le code "continuez". donc je dois le mettre dans sa propre méthode. donc je dois refaire toute la configuration qui a mené au dialogue encore une fois. mauvaise conception IMHO.

8voto

Daniel Points 91
PasswordDialog dlg = new PasswordDialog(this);

if(dlg.showDialog() == DialogResult.OK)

{

    //blabla, anything your self

}

public class PasswordDialog extends Dialog
{
    int dialogResult;
    Handler mHandler ;

    public PasswordDialog(Activity context, String mailName, boolean retry)
    {

        super(context);
        setOwnerActivity(context);
        onCreate();
        TextView promptLbl = (TextView) findViewById(R.id.promptLbl);
        promptLbl.setText("Input password/n" + mailName);
    }
    public int getDialogResult()
    {
        return dialogResult;
    }
    public void setDialogResult(int dialogResult)
    {
        this.dialogResult = dialogResult;
    }
    /** Called when the activity is first created. */

    public void onCreate() {
        setContentView(R.layout.password_dialog);
        findViewById(R.id.cancelBtn).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View paramView)
            {
                endDialog(DialogResult.CANCEL);
            }
            });
        findViewById(R.id.okBtn).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View paramView)
            {
                endDialog(DialogResult.OK);
            }
            });
        }

    public void endDialog(int result)
    {
        dismiss();
        setDialogResult(result);
        Message m = mHandler.obtainMessage();
        mHandler.sendMessage(m);
    }

    public int showDialog()
    {
        mHandler = new Handler() {
            @Override
              public void handleMessage(Message mesg) {
                  // process incoming messages here
                //super.handleMessage(msg);
                throw new RuntimeException();
              }
          };
        super.show();
        try {
            Looper.getMainLooper().loop();
        }
        catch(RuntimeException e2)
        {
        }
        return dialogResult;
    }

}

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