Dialoge / AlertDialogs: So blockieren Sie die Ausführung, während der Dialog aktiv ist (.NET-Stil)

73

Ich komme aus der .NET-Umgebung und möchte nun verstehen, wie Dialoge in Android funktionieren.

In .NET wird beim Aufrufen MessageBox.Show(...)ein Popup-Dialogfeld erstellt und angezeigt. Beim Aufruf von Show kann ich angeben, welche Schaltflächen im Popup verfügbar sein sollen, zum Beispiel:

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

Wie Sie sehen können, gibt der Aufruf von Show ein DialogResult zurück, wenn eine Schaltfläche im Popup gedrückt wird, und teilt mir mit, auf welche Schaltfläche geklickt wurde. Beachten Sie, dass in .NET die Ausführung in der Zeile angehalten wird, in der der Aufruf Show(...)erfolgt, sodass der Wert zurückgegeben werden kann, wenn eine Taste gedrückt wird.

Wenn ich im obigen Beispiel "Nein" drücke, ist myDialogResult gleich

myDialogResult == DialogResult.No

Da ich die .NET-Methode zum Verwenden / Erstellen von Popups sehr einfach und intuitiv finde, möchte ich diese Art der Erstellung von Popups auch in Android.

Die Frage ist also, ob jemand weiß, wie man die Ausführung wie mit "stoppt" MessageBox.Showund dann einen Wert zurückgibt, wenn die Taste gedrückt wird (und der Dialog verschwindet).

Bearbeiten 1

Um es etwas klarer zu machen:

Ich muss die Ausführung anhalten und warten, bis der Benutzer eine Schaltfläche zum Klicken im Popup ausgewählt hat. Der Code, der auf den Aufruf zum Anzeigen des Dialogfelds folgt, hängt davon ab, auf welche Schaltfläche im Dialogfeld geklickt wird.

Deshalb kann ich nicht verwenden, was Erich und Alex vorschlagen, da das Schreiben von Code in den unten vorgeschlagenen onClick-Methoden nicht funktioniert. Der Grund ist, dass ich die "normale Ausführung" nicht fortsetzen kann. Lassen Sie mich ein Beispiel nehmen:

Lassen Sie mich ein Beispiel nehmen:

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

Wenn ich wollte, dass die Ausführung von der Auswahl im Popup abhängt, müsste ich irgendwie alle Variablen in der "normalen Ausführung" (in diesem Fall nextStep) in den onClick-Methoden verfügbar machen, und das klingt für mich höllisch.

Bearbeiten 2

Ein weiteres offensichtliches Beispiel wäre ein Popup mit der Option " Möchten Sie fortfahren" mit den Optionen "Ja" und "Nein" .

Wenn der Benutzer "Ja" drückt, sollte die gesamte Methode abgebrochen werden, andernfalls sollte die Ausführung fortgesetzt werden. Wie löst man das gut?

Ted
quelle
Sehen Sie, ob der hinzugefügte Absatz von
Fupsduck
4
Alternativ können Sie Ihren "Dialog" auch als Aktivität gestalten, die das gleiche Erscheinungsbild wie ein Dialog hat. Wenn Ihr Dialog viel Logik enthält, ist es möglicherweise einfacher, diese Methode zu implementieren.
Erich Douglass
2
In Bezug auf den Warndialog ist .NET großartig und Android ist scheiße. In einigen Fällen benötige ich MessageBox, um das Debuggen zu erleichtern. In .NET wird der Code nach der MessageBox erst ausgeführt, wenn Sie die MessageBox schließen. In Android funktioniert es jedoch nicht. Ich denke, in Windows gibt es eine andere Nachrichtenschleife, wenn ein modaler Dialog angezeigt wird. In Android verwenden das Fenster und der Dialog meiner Meinung nach dieselbe Nachrichtenschleife.
Zach
Statt mit If (nextStep == 1) { }und If (nextStep == 2) { }müssen Sie eine Lücke genannt haben, sagen wir, public void nextStep1und public void nextStep2die aufgerufen werden , wenn der Benutzer eine bestimmte Schaltfläche klickt. Wenn sie Code-Nachwörter gemeinsam nutzen, können Sie eine weitere Leere machen, die sie jeweils mit dem Rest Ihres Codes als Nachwörter aufrufen.
Cullub
Ich denke, der Android-Typ @Romain Guy hat gerade gesagt, dass "Sie kein Programm entwerfen sollten, das schön und sauber aussieht, um eine Wahl zu treffen und entsprechend der Wahl zu handeln". Wenn es eine Folge ähnlicher Auswahlmöglichkeiten gibt, die miteinander in Beziehung stehen, sind möglicherweise 100-mal Codezeilen in Android erforderlich. Ich weiß nicht, was die Schwierigkeit oder Nebenwirkung ist, dies zur Android-Bibliothek hinzuzufügen, aber ich denke, es ist vielleicht schwierig von ihnen.
rml

Antworten:

49

Ted, das willst du eigentlich nicht :) Der Hauptgrund ist, dass du, wenn du den UI-Thread blockierst, während du einen Dialog anzeigst, den Thread blockierst, der für das Zeichnen und Behandeln der Ereignisse deines Dialogs zuständig ist. Dies bedeutet, dass Ihr Dialog nicht mehr reagiert. Sie verursachen auch ANRs, wenn der Benutzer länger als einige Sekunden braucht, um auf das Dialogfeld zu klicken.

Erichs Antwort ist genau das, was Sie brauchen. Ich weiß, dass es nicht das ist, was du willst , aber das spielt keine Rolle. Wir haben Android entwickelt, um zu verhindern, dass Entwickler synchrone Dialoge schreiben, sodass Sie nicht wirklich eine große Auswahl haben.

Romain Guy
quelle
20
Es ist ein Chaos, weil Sie Ihren Code so gestalten, wie es nicht für Android gedacht ist. Mach es einfach anders . Wenn Sie sich weigern, ist es Ihr Problem. Anstatt zum Beispiel 3 blockierende Dialoge zu verwenden (was ich übrigens als eine schreckliche und faule Benutzeroberfläche empfinde), werden alle Fragen nur dann beantwortet, wenn der Benutzer bestätigt, dass Sie anfangen, das zu tun, was auch immer Ihre App ist soll tun. Sie haben eine Frage gestellt, die wir beantwortet haben, und bisher haben Sie nur gesagt, dass Ihnen unsere Antworten nicht gefallen. Entschuldigung, aber sie werden sich nicht ändern.
Romain Guy
60
Hör auf, den Leuten zu sagen, dass sie nicht versuchen sollen, das zu tun, was sie tun wollen. Wenn etwas "schrecklich und faul" ist, wäre es das (Antwort). Natürlich können Sie in Android modale Dialoge erstellen, Sie müssen nur mehr Code schreiben. Aus der Sicht eines Benutzers ist an dieser Benutzeroberfläche nichts Schlechtes. Viele UI-Frameworks, nicht nur Windows, unterstützen dieses Konzept. Wenn es eine einfache einzeilige Antwort gegeben hätte, hätte das Poster die Frage wahrscheinlich nicht stellen müssen. Wenn Sie seine Frage nicht beantworten möchten, lassen Sie es einfach in Ruhe.
Nate
6
@radhoo Aufgrund dieser kleinen Details sehe ich so viele schreckliche mobile Apps (iOS-Apps, die von einem Java-Typ entworfen wurden, und Android-Aberrationen, die von C ++ - Leuten entworfen wurden) (zum Beispiel). Sie müssen die Plattform, auf der Sie arbeiten, lernen und verstehen und sich nicht unbedingt mit Ihren eigenen Ideen durchsetzen. Jede Plattform hat ihre Stärken und Schwächen, ob es Ihnen gefällt oder nicht. Das Lebenszyklusmodell in Android ist so konzipiert, dass Sie damit umgehen und lernen, wie man es umgibt.
Martin Marconcini
8
@rml Ich arbeite im Android-Framework-Team und wir haben das Framework speziell so konzipiert, dass es keine modalen Dialoge enthält, die den aktuellen Ausführungsthread blockieren. Ich weiß, wie es gemacht werden könnte, aber es ist nicht das Modell, das wir für Android gewählt haben.
Romain Guy
35
Bitte beachten Sie, dass das OP den UI- Thread sicherlich nicht stoppen wollte, sondern nur den Benutzer- Workflow blockieren wollte . Da dies ein gültiger und allgemeiner Anwendungsfall ist (da Benutzer selten mehrere parallele Interaktionen mit ihren Gadgets durchführen und Systeme häufig auf sie warten müssen), ist es selbstverständlich, eine triviale modale Dialog-API zu erwarten, die nahtlos mit der Realität des "Single-Threaded-Benutzers" übereinstimmt . Es ist verständlich, wenn es nicht einfach ist, es gut zu machen. Aber wenn das Android-Team einen intelligenten Weg finden könnte, um es so trivial wie in der Frage dargestellt zu machen, könnte es uns allen nur helfen. Danke!
Gr.
21

In Android unterscheidet sich die Struktur von .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();

Sie erhalten einen Dialog mit zwei Schaltflächen und Sie behandeln die Schaltflächenklicks mit Rückrufen. Möglicherweise können Sie Code schreiben, um die Syntax .NET ähnlicher zu machen, aber der Dialoglebenszyklus ist ziemlich eng miteinander verbunden Activity, sodass es am Ende möglicherweise mehr Probleme gibt, als es wert ist. Weitere Dialogreferenzen finden Sie hier .

Erich Douglass
quelle
4
Es gibt also keinen "Modal" -Dialog in Android? Du kannst es nicht ernst meinen.
Kommen Sie
20

Eine vereinfachte Version von Daniels Antwort oben. Diese Funktion erhält vom Benutzer in einem Warndialog ein Ja oder Nein, kann jedoch leicht geändert werden, um andere Eingaben zu erhalten.

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;
}
MindSpiker
quelle
Danke, dieser funktioniert gut. Ich bevorzuge Erichs Weg, aber er blockiert nicht die Ausführung (die Lösung, die ich oft benutze). Zumindest funktioniert Ihr Weg wie von der Frage beabsichtigt und die Antwort ist interessant.
Solostaran14
Dies ist die verwandteste Antwort auf die Frage und eine kreative Lösung. Sie schlägt jedoch manchmal mit einem schwerwiegenden Fehler wie diesem fehl: A / libc ﹕ Schwerwiegendes Signal 11 (SIGSEGV), Code 1, Fehleradresse 0x1 in tid 274 ... Is Hat jemand eine Lösung dafür?
rml
Ich möchte sagen, dass dies auch für HTTP-Anfragen funktioniert. Ich habe gerade eine HTTP-Anfrage über Volley gestellt, die die Idee hat, dass der Code (in der Hauptbedrohung) fortgesetzt werden muss, während die HTTP-Anfrage ausgeführt wird. Toller Service, warum lassen Sie uns nicht als Programmierer entscheiden, ob wir sitzen und Gymnastik mit einer endlosen Ruftiefe machen wollen oder ob wir unser eigenes Threading machen wollen, wenn ja? Ihr hervorragendes Beispiel oben hat ohne eine einzige Schraube oder Mutter funktioniert. Und jetzt habe ich modale HTTP-Aufrufe. Ich habe den AlertDialog jedoch über normales Threading aussortiert (!). Wo kann man mit dem Rest von Ihnen teilen
David Svarrer
11

In Android sind Dialoge asynchron, sodass Sie Ihren Code etwas anders strukturieren müssen.

In C # lief Ihre Logik also ungefähr so ​​im 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
}

Für Android muss es weniger ordentlich sein. Stellen Sie es sich so vor. Sie werden eine solche haben OnClickListener:

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

Was dann von folgenden Methoden unterstützt wird:

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

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

void endThings() {
    //clean up here
}

Was also eine Methode war, ist jetzt vier. Es mag nicht so ordentlich erscheinen, aber ich fürchte, so funktioniert es.

Dave Webb
quelle
1
Danke Dave! Ja, das habe ich aus all diesen Antworten gelernt. Leider muss ich sagen ... Danke nochmal =)
Ted
3
Ich finde das etwas frustrierend, weil mein Ausführungsfluss manchmal den Dialog umgeht, wenn alles in Ordnung ist. Wenn es ein Problem gibt, frage ich "mach weiter" oder "vergiss es". Jetzt habe ich zwei Möglichkeiten, um zum Keep-Going-Code zu gelangen. also muss ich das in seine eigene Methode setzen. Also muss ich das gesamte Setup, das zum Dialog gelangt ist, noch einmal wiederholen. schlechtes Design IMHO.
Steve
9
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;
    }

}
Daniel
quelle
5

Bei dem Versuch, Speicher und Leistung zu optimieren, sind Dialoge in Android asynchron (sie werden auch aus diesem Grund verwaltet). Aus der Windows-Welt kommend, sind Sie an modale Dialoge gewöhnt. Android-Dialoge sind modal, aber in Bezug auf die Ausführung eher nicht modal. Die Ausführung wird nach dem Anzeigen eines Dialogfelds nicht gestoppt.

Die beste Beschreibung der Dialoge in Android, die ich gesehen habe, ist in "Pro Android" http://www.apress.com/book/view/1430215968

Dies ist keine perfekte Erklärung, aber es sollte Ihnen helfen, die Unterschiede zwischen Dialogen in Windows und Android in den Griff zu bekommen. In Windows möchten Sie A ausführen, eine Frage mit einem Dialogfeld stellen und dann B oder C ausführen. In Android Design A mit dem gesamten Code, den Sie für B und C in onClick () der OnClickListener (s) für das Dialogfeld benötigen . Dann mache A und starte den Dialog. Du bist fertig mit A! Wenn der Benutzer auf eine Schaltfläche klickt, wird B oder C ausgeführt.

Windows
-------
A code
launch dialog
user picks B or C
B or C code
done!

Android
-------
OnClick for B code (does not get executed yet)
OnClick for C code (does not get executed yet)
A code
launch dialog
done!
user picks B or C
fupsduck
quelle
1
Wenn dieser Thread nichts anderes enthält, ist dies Ihr Fall. Aber du hast immer etwas anderes da. Sie müssen also verhindern, dass andere Dinge passieren, oder Dutzende oder Millionen von Fällen behandeln, die den Status ändern und dazu führen, dass B- oder C-Funktionen nicht richtig funktionieren. Der Android-Weg macht es zu kompliziert.
rml
Es ist nicht wirklich komplizierter, es ist einfach anders.
Cullub
2
Wenn es viele ähnliche Fragen gibt, die nacheinander beantwortet werden müssen, und jede Auswahl den späteren Prozess beeinflusst, wird es ein großes Durcheinander sein, das in Android verwendet wird, aber es wird viel einfacher sein, Windows-Dialoge zu verwenden. ABSOLUT NICHT NUR anders.
rml
5

Entwickler von Android und iOS haben entschieden, dass sie leistungsstark und intelligent genug sind, um die Modal Dialog-Konzeption abzulehnen (die bereits seit vielen Jahren auf dem Markt ist und bisher niemanden gestört hat), leider für uns. Ich glaube, dass es eine Lösung für Android gibt - da Sie Dialoge von Nicht-UI-Threads mit der Runnable-Klasse anzeigen können, sollte es eine Möglichkeit geben, in diesem Thread (Nicht-UI) zu warten, bis der Dialog beendet ist.

Edit: Hier ist meine Lösung, es funktioniert super:

    int pressedButtonID;
    private final Semaphore dialogSemaphore = new Semaphore(0, true);
    final Runnable mMyDialog = new Runnable()
    {
        public void run()
        {
            AlertDialog errorDialog = new AlertDialog.Builder( [your activity object here] ).create();
            errorDialog.setMessage("My dialog!");
            errorDialog.setButton("My Button1", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    pressedButtonID = MY_BUTTON_ID1;
                    dialogSemaphore.release();
                    }
                });
            errorDialog.setButton2("My Button2", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    pressedButtonID = MY_BUTTON_ID2;
                    dialogSemaphore.release();
                    }
                });
            errorDialog.setCancelable(false);
            errorDialog.show();
        }
    };

    public int ShowMyModalDialog()  //should be called from non-UI thread
    {
        pressedButtonID = MY_BUTTON_INVALID_ID;
        runOnUiThread(mMyDialog);
        try
        {
            dialogSemaphore.acquire();
        }
        catch (InterruptedException e)
        {
        }
        return pressedButtonID;
    }
art926
quelle
4

Ted, wie Sie wahrscheinlich herausgefunden haben, können Sie das auf Android leider nicht. Dialoge sind modal, aber asynchron und stören definitiv die Sequenz, die Sie einrichten möchten, wie Sie es unter .NET (oder Windows) getan hätten. Sie müssen Ihren Code drehen und eine Logik brechen, die anhand Ihres Beispiels sehr einfach zu befolgen gewesen wäre.

Ein weiteres sehr einfaches Beispiel ist das Speichern von Daten in einer Datei, um festzustellen, ob die Datei bereits vorhanden ist, und um das Überschreiben zu bitten oder nicht. Anstatt einen Dialog anzuzeigen und eine if-Anweisung zu haben, um auf das Ergebnis zu reagieren (Ja / Nein), müssen Sie Rückrufe (in Java Listener genannt) verwenden und Ihre Logik in mehrere Funktionen aufteilen.

Wenn unter Windows ein Dialogfeld angezeigt wird, wird die Nachrichtenpumpe im Hintergrund fortgesetzt (nur die aktuell verarbeitete Nachricht wird gehalten), und das funktioniert einwandfrei. Auf diese Weise können Benutzer Ihre App verschieben und neu malen, während Sie beispielsweise ein Dialogfeld anzeigen. WinMo unterstützt synchrone modale Dialoge, ebenso wie BlackBerry, jedoch nicht Android.

user545076
quelle
15
Microsoft hat vor zwei Jahrzehnten modale Dialogfelder ohne Blockierung implementiert, die den Code sehr flüssig und leicht lesbar machen (jeder Windows-Entwickler kann dies bestätigen), indem eine zweite Nachrichtenpumpe verwendet wurde, um die Dialogfeldinteraktion zu handhaben, während Nachrichten ohne Dialogfeld an gesendet werden die App, die entsperrt bleibt, während das Dialogfeld angezeigt wird. Android hat keine solche Implementierung, daher müssen Sie Ihren Code aufteilen. Android-Designer sagen uns lieber "das ist unser Weg oder die Autobahn", anstatt zuzuhören, was ihre Kunden (Entwickler) brauchen
user545076
2

Die sauberste und einfachste Lösung besteht darin, eine eigene Listener-Oberfläche zu verwenden, sodass Ihr Listener mit dem Rückgabewert aufgerufen wird, wenn der Benutzer auf die Schaltfläche OK klickt. Diese Methode macht nichts Besonderes oder Kompliziertes und respektiert die Android-Prinzipien.

Definieren Sie Ihre Listener-Oberfläche wie folgt:

public interface EditListener
/* Used to get an integer return value from a dialog
 * 
 */
{
 void returnValue(int value); 
}

Für meine Anwendung habe ich eine EditValue-Klasse erstellt, die AlertDialog verwendet und die ich immer dann aufrufe, wenn ich einen ganzzahligen Wert bearbeiten möchte. Beachten Sie, wie die EditListener-Schnittstelle als Argument an diesen Code übergeben wird. Wenn der Benutzer auf die Schaltfläche OK klickt, wird der Wert über die EditListener-Methode an Ihren aufrufenden Code zurückgegeben:

public final class EditValue
/* Used to edit a value using an alert dialog
 * The edited value is returned via the returnValue method of the supplied EditListener             interface
 * Could be modified with different constructors to edit double/float etc
 */
{
 public EditValue(final Activity parent, int value, String title, String message,
                  final EditListener editListener)
 {AlertDialog.Builder alert= new AlertDialog.Builder(parent);
  if(title==null) title= message;
  else if(message==null) message= title;
  if(title!=null) alert.setTitle(title);
  if(message!=null) alert.setMessage(message);

  // Set an EditText view to get user input 
  final EditText input = new EditText(parent);
  input.setText(String.valueOf(value));
  input.setInputType(InputType.TYPE_CLASS_NUMBER);
  alert.setView(input);

  alert.setPositiveButton("OK",new DialogInterface.OnClickListener()
  {public void onClick(DialogInterface dialog, int which)
   {try
    {int newValue= Integer.valueOf(input.getText().toString());
     editListener.returnValue(newValue);
     dialog.dismiss();
    }catch(NumberFormatException err) { }
   }
  });

  alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
  {public void onClick(DialogInterface dialog, int which)
   {dialog.dismiss();
    }
  });

  alert.show();
 }
}

Wenn Sie EditValue verwenden, müssen Sie Ihren EditListener deklarieren. Jetzt können Sie auf den Rückgabewert zugreifen und das tun, was Sie tun möchten:

 new EditValue(main,AnchorManager.anchorageLimit,
               main.res.getString(R.string.config_anchorage_limit),null,
               new EditListener()
 {public void returnValue(int value) {AnchorManager.anchorageLimit= value;}
  }
 );
JohnnyBeGood
quelle
1

Ich bin neu in der Android / Java-Welt und war überrascht, hier herauszufinden (es sei denn, ich verstehe nicht, was ich lese), dass modale Dialoge nicht funktionieren. Aus einigen für mich momentan sehr dunklen Gründen habe ich dieses "ShowMessage" -Äquivalent mit einer OK-Schaltfläche erhalten, die auf meinem Tablet sehr modal funktioniert.

Aus meinem TDialogs.java-Modul:

class DialogMes 
{

  AlertDialog alertDialog ;
  private final Message NO_HANDLER = null;
  public DialogMes(Activity parent,String aTitle, String mes)
  {
    alertDialog = new AlertDialog.Builder(parent).create();
    alertDialog.setTitle(aTitle);    
    alertDialog.setMessage(mes) ;  
    alertDialog.setButton("OK",NO_HANDLER) ;    
    alertDialog.show() ; 
  } 
}

Hier ist ein Teil des Testcodes:

public class TestDialogsActivity extends Activity implements DlgConfirmEvent
{

   @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Button btShowMessage = (Button) findViewById(R.id.btShowMessage);
    btShowMessage.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) 
      {
        DialogMes dlgMes = new DialogMes( TestDialogsActivity.this,"Message","life is good") ;                
      }  
    }); 

Ich habe auch ein modales Ja / Nein-Dialogfeld implementiert, das dem oben von JohnnyBeGood vorgeschlagenen Schnittstellenansatz folgt, und es funktioniert auch ziemlich gut.

Korrektur:

Meine Antwort ist nicht relevant für die Frage, die ich missverstanden habe. Aus irgendeinem Grund interpretierte ich M. Romain Guy "Sie wollen das nicht" als ein Nein Nein zu modalen Dialogen. Ich hätte lesen sollen: "Das willst du nicht ... so".

Ich entschuldige mich.

Guyt
quelle
1

Umschreiben:

Es gibt radikale Unterschiede zwischen der mobilen und der Desktop-Umgebung sowie zwischen der Art und Weise, wie Anwendungen vor einigen Jahren und heute entwickelt wurden:

a) Mobile Geräte müssen Energie sparen. Ein Teil des Wertes, den sie bieten. Sie müssen also Ressourcen sparen. Threads sind eine teure Ressource. Das Anhalten des Fortschritts eines Threads ist eine inakzeptable Verschwendung dieser Ressource.

b) Heutzutage ist der Benutzer viel anspruchsvoller. Wir sind der Meinung, dass es eine voll funktionsfähige CPU und einen möglichst geringen Energieverbrauch verdient, um sie zu unterstützen. Die Anwendung ist nicht allein auf dem Gerät, es wird eine unbekannte Anzahl anderer Apps gleichzeitig ausgeführt, und Ihre App ist nicht unbedingt die dringendste.

c) Sperren auf Systemebene sind keine Option: Ein mobiles Gerät arbeitet mit einer Reihe von Ereignissen und Diensten im Hintergrund und es ist nicht richtig, dass eines von ihnen von einer Anwendung gesperrt werden kann.

Denken Sie an den Benutzer, der einen Anruf erhält, während Ihre "Systemsperre" funktioniert ...

Basierend auf den obigen Fakten lautet die Antwort auf die vorgeschlagene Frage:

  • Gibt es eine praktikable Möglichkeit, einen Dialog zu erstellen, der den Hauptthread bis zu einer Antwort des Benutzers blockiert?

Nein. Problemumgehungen verschlechtern die Benutzererfahrung und können dazu führen, dass das System selbst beschuldigt wird. Dies ist unfair und bestraft die Plattform und alle ihre Entwickler.

  • Gibt es eine Möglichkeit, das gesamte System mit einem Dialog zu blockieren?

Nein, dies ist auf der Plattform strengstens verboten. Keine Anwendung kann den Betrieb des Systems oder anderer Anwendungen stören.

  • Ich muss meine Anwendung umgestalten oder meine Programmierweise überdenken, um sie an die Architektur des mobilen Android-Systems anzupassen.

Ja. Einschließlich dieses Aspekts.

Renascienza
quelle
Dies klingt nicht nach einer guten Antwort, eher nach einem Schimpfen, bitte bearbeiten oder löschen ...
user1781290
0

Sie setzen Onclick-Listener auf Ihre Schaltflächen. dissmis dialog und mach deine aktion. Ich muss nichts aufhalten

protected Dialog onCreateDialog(int id) {
  return new AlertDialog.Builder(this).setTitle(R.string.no_connection).setIcon(android.R.drawable.ic_dialog_alert).setView(textEntryView).setPositiveButton(R.string.exit, new DialogInterface.OnClickListener() 
{

   public void onClick(DialogInterface dialog, int whichButton) {

  // Here goes what you want to do
  }

})
}

aufrufen - ex - showDialog (DIALOG_ERROR_PREF);

Mehr http://developer.android.com/guide/topics/ui/dialogs.html

Alex Volovoy
quelle
Hey, das war nicht wirklich das, was ich wollte, denke ich. Immer wenn ein Popup angezeigt wird, sollte der folgende Code erst ausgeführt werden, nachdem ich eine der Schaltflächen im Popup gedrückt habe. Der Wert des Tastendrucks sollte an den Anrufer zurückgegeben werden, damit der Anrufer dann entscheiden kann, was zu tun ist ... Ich werde meine Frage oben aktualisieren.
Ted
2
Da es nicht wirklich ein .Net ist, denke ich, dass Sie sich anpassen müssen. Und es ist auch kein Desktop. Brechen Sie Ihren Fluss in Ereignisse. Sie haben eine Aktion ausgeführt, um den Dialog anzuzeigen. Jetzt reagiert der Benutzer mit dem Drücken der Tasten. Rufen Sie doDamage () auf. dontDoDamage () -Methoden. Und weiter von dort
Alex Volovoy
0

Nur um Ihre Frage zu beantworten ... Übrigens, ich bin 9 Monate zu spät: D ... es gibt eine "Problemumgehung" 4 für diese Art von Problemen. dh

new AlertDialog.Builder(some_class.this).setTitle("bla").setMessage("bla bla").show();
wait();

füge einfach wait () hinzu;

und sie in den OnClickListener die Klasse beginnen wieder mit benachrichtigen () so etwas wie diesem

@Override
    public void onClick(DialogInterface dialog, int item) {
        Toast.makeText(getApplicationContext(), "test", Toast.LENGTH_LONG).show();
        **notify**();
        dialog.cancel();
    }

Die gleiche Problemumgehung gilt für 4 Toasts und andere asynchrone Aufrufe in Android

mc_fish
quelle
Danke =) Wenn ich mich jemals wieder mit Android beschäftige, werde ich es versuchen. Ich habe jedoch Android fallen gelassen. Zumindest für jetzt.
Ted
hehe ich sagte, es tut mir leid: P hatte nur das gleiche Problem und wollte, dass die Leute die Problemumgehung kennen ... natürlich ist es nicht so einfach ... ich brauchte schließlich einen neuen Thread und 2 neue Runnables, die synchronisiert wurden und so auf ... ein kleines teuflisches Problem, wenn jemand den vollständigen Code benötigt ... fragen Sie :) es ist groß, ich meine den Code um oh hm
mc_fish
Hehe, danke für die Info =) Ich werde mich daran erinnern, wenn ich wieder in die Android-Entwicklung komme =)
Ted
2
Wenn Sie diese "Problemumgehung" verwenden, wird in Ihrer App ein ANR-Fehler angezeigt, wenn Ihr Benutzer nicht mit 10 Sekunden antwortet. Das wird nicht funktionieren.
Justin Breitfeller
0

Versuchen Sie dies in einem Thread (nicht im UI-Thread):

final CountDownLatch latch = new CountDownLatch(1);
handler.post(new Runnable() {
  @Override
  public void run() {
    OnClickListener okListener = new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
      latch.countDown();
    }
  };

  AlertDialog dialog = new AlertDialog.Builder(context).setTitle(title)
    .setMessage(msg).setPositiveButton("OK", okListener).create();
  dialog.show();
}
});
try {
  latch.await();
} catch (InterruptedException e) {
  e.printStackTrace();
}
Geso
quelle
0
UserSelect =null

AlertDialog.Builder builder = new Builder(ImonaAndroidApp.LoginScreen);
            builder.setMessage("you message");
            builder.setPositiveButton("OK", new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    UserSelect = true ;

                }
            });

            builder.setNegativeButton("Cancel", new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    UserSelect = false ;

                }
            });
           // in UI thread
        builder.show();             
        // wait until the user select
            while(UserSelect ==null);
Mohammed Subhi Sheikh Quroush
quelle
Ihre letzte Zeile "while (UserSelect == null);" - Dieser ist ein Mörder. Ihr Telefon tritt in eine Endlosschleife ein und heizt die CPU ohne Grund auf, entleert den Akku und verlangsamt das gesamte Telefon.
David Svarrer
0

Ich verwende Xamarin.Android (MonoDroid) und habe Anforderungen für die Entwicklung des Bestätigungsfelds für die Blockierung der Benutzeroberfläche. Ich werde nicht mit dem Kunden streiten, weil ich gute Gründe dafür sehe, warum er das will ( Details hier ), also muss ich dies implementieren. Ich habe oben @Daniel und @MindSpiker ausprobiert, aber diese funktionierten unter MonoForAndroid nicht. Sobald die Nachricht zwischen den Threads gesendet wird, stürzt die App ab. Ich gehe davon aus, dass es etwas mit Xamarin-Mapping zu tun hat.

Am Ende habe ich einen separaten Thread vom UI-Thread erstellt, diesen dann blockiert und wie folgt auf die Benutzerantwort gewartet:

// (since the controllers code is shared cross-platforms)
protected void RunConfirmAction(Action runnableAction)
{
    if (runnableAction != null)
    {
        if (Core.Platform.IsAndroid)
        {
            var confirmThread = new Thread(() => runnableAction());
            confirmThread.Start();
        }
        else
        {
            runnableAction();
        }
    }
}

// The call to the logout method has now changed like this:
RunConfirmAction(Logout);

// the implemtation of the MessageBox waiting is like this:
public DialogResult MessageBoxShow(string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
{
    if (_CurrentContext != null && _CurrentContext.Screen != null && MainForm.MainActivity != null)
    {
        Action<bool> callback = OnConfirmCallBack;
        _IsCurrentlyInConfirmProcess = true;
        Action messageBoxDelegate = () => MessageBox.Show(((Activity)MainForm.MainActivity), callback, message, caption, buttons);
        RunOnMainUiThread(messageBoxDelegate);
        while (_IsCurrentlyInConfirmProcess)
        {
            Thread.Sleep(1000);
        }               
    }
    else
    {
        LogHandler.LogError("Trying to display a Message box with no activity in the CurrentContext. Message was: " + message);
    }
    return _ConfirmBoxResult ? DialogResult.OK : DialogResult.No;

}

private void OnConfirmCallBack(bool confirmResult)
{
    _ConfirmBoxResult = confirmResult;
    _IsCurrentlyInConfirmProcess = false;
}

private bool _ConfirmBoxResult = false;
private bool _IsCurrentlyInConfirmProcess = false;

Ausführliche Informationen dazu finden Sie in meinem Blog-Beitrag hier

Hat AlTaiar
quelle
0

Lassen Sie mich als Dankeschön an die StackOverflow-Community etwas Nettes mit Ihnen teilen, wo ich das obige Beispiel im Android-Code für HTTP-Aufrufe verwendet habe, der jetzt MODAL anstelle des üblichen zusätzlichen Threads und der Komplexität des Zusammenführens der Threads durch Verwendung wird vom etwas eigenartigen Einfädeln. (Dies funktioniert gerade in unserer App - 15. Oktober 2020)

public JSONArray genericHttpModal(Context context, final String url, final JSONObject request) {

    this.url = url;    
    genericHttpRequestQueue = Volley.newRequestQueue(context);      
    class MyJsonReturn {
        JSONArray returnJsonArray;

        public void set(JSONArray i) {
            returnJsonArray = i;
        }

        public void set(String i) {
            try {
                returnJsonArray.put(0, i);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        public JSONArray get() {
            return returnJsonArray;
        }
    }

    final MyJsonReturn mymy = new MyJsonReturn();

    // Positive Response / HTTP OK.
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            throw new RuntimeException();
        }
    };

    final Response.Listener responseListener = new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            try {
                mymy.set(new JSONArray(response));
            } catch (JSONException e) {
                mymy.set("[{\"JSONException:\"" + e.getMessage() + "\"}]");
            }
            handler.sendMessage(handler.obtainMessage());
        }
    };

    // Negative Response / HTTP NOT OK
    final Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            result = "fail";

            try {
                mymy.set(new JSONArray("[{\"JSONException:\"" + result + "\"}]"));
            } catch (JSONException e) {
                mymy.set("[{\"JSONException:\"" + e.getMessage() + "\"}]");
            }
            handler.sendMessage(handler.obtainMessage());
        }
    };


    final StringRequest httpRequest = new StringRequest(Request.Method.POST, URL_POINTER + url,
            responseListener,
            errorListener) {

        // Here the mRequestQueue handler will get the parameters for this request here.
        // Ref: /programming/33573803/how-to-send-a-post-request-using-volley-with-string-body#33578202
        // Ref: Multi Threaded solution 14 Oct 2020 (David Svarrer) : /programming/2028697/dialogs-alertdialogs-how-to-block-execution-while-dialog-is-up-net-style (This stackoverflow here)
        @Override
        protected java.util.Map<String, String> getParams() throws AuthFailureError {
            return jsonObjectToMap(request);
        }
    };
    httpRequest.setShouldCache(false); // Elijah: Could work on dropping the cache !!!
    genericHttpRequestQueue.add(httpRequest);    

    try {
        Looper.loop();
    } catch (RuntimeException re) {
    }
    return mymy.get();
}
David Svarrer
quelle
-1

Dies ist der einfachste Weg:

new AlertDialog.Builder(this).setTitle("title").setMessage("message").create().show();
Cytown
quelle
Ja, aber das löst das Problem nicht. Ich spreche an, ich denke, siehe meine "EDIT 1" in meiner Frage aboive =) Grüße
Ted