2010-12-07 14 views
34

Ich möchte eine Methode implementieren, die einen Dialog anzeigt, wartet, bis der Dialog geschlossen wird, und gibt dann ein Ergebnis abhängig von dem Dialoginhalt zurück. Ist das möglich?Android: Warten auf Benutzereingabe von Dialog?

public String getUserInput() 
{ 
    //do something to show dialog 
    String input = //get input from dialog 
    return input; 
} 

Ich versuche tatsächlich eine Schnittstelle zu implementieren, die Methode „public String GetUserInput()“ hat, wo die zurückgegebene Zeichenfolge über Dialog abgerufen werden. Dies ist einfach in Java, scheint unmöglich in Android?

EDIT: Buchung einige Codebeispiel als

in Kommentar angefordert

getInput() muss von einem Hintergrund-Thread aufgerufen werden (ich es von einem AsynchTask nennen). getInput() zeigt einen Dialog an und Aufrufe warten. Wenn die OK-Schaltfläche im Dialogfeld gedrückt wird, legt das Dialogfeld die Benutzereingabe in einer Mitgliedsvariablen fest und ruft notify auf. Wenn notify aufgerufen wird, wird getInput() fortgesetzt und gibt die Membervariable zurück.

String m_Input; 

public synchronized String getInput() 
{ 
    runOnUiThread(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      AlertDialog.Builder alert = new AlertDialog.Builder(context); 
      //customize alert dialog to allow desired input 
      alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { 
      public void onClick(DialogInterface dialog, int whichButton) 
      { 
          m_Input = alert.getCustomInput(); 
          notify(); 
      } 
     }); 
     alert.show(); 
     } 
    }); 

    try 
    { 
     wait(); 
    } 
    catch (InterruptedException e) 
    { 
    } 

    return m_Input; 
} 
+5

Sie können nicht auf den Benutzer in einer Methode warten, die im UI-Thread aufgerufen wird. Sie müssen also entweder zu einem ereignisgesteuerten Modell des Programmablaufs wechseln oder dieses aus einem Hintergrundthread aufrufen, der warten kann, bis eine onWhatever() -Methode im Benutzeroberflächenthread aufgerufen wird, die auf Ihre Hintergrundmethode wartet. –

+0

Ich verstehe nicht wirklich, können Sie erklären, wie ich dies von einem Hintergrund-Thread nennen würde, und dann meine Zeichenfolge auf Was auch immer() zurückgeben? – ab11

+0

Wenn Sie den Benutzeroberflächen-Thread für mehr als 3 (?) Blockieren würden, würden Sie nach drei Sekunden ein ANR-Dialogfeld erhalten, in dem Sie gefragt werden, ob Sie die Anwendung schließen möchten. Führen Sie niemals blockierende Inhalte im UI-Thread von Android aus. –

Antwort

11

Dank für alle Rückgespräch, konnte ich dieses lösen, das einen Hintergrundthread zusammen mit einem wait() benutzt und notify (). Ich erkenne, dass dies nicht die beste Idee für das gegebene Paradigma ist, aber es war notwendig, sich einer Bibliothek anzupassen, mit der ich arbeite.

+1

können Sie etwas Code posten? – Caner

+2

aktualisiert meine Antwort mit einem Code – ab11

+0

vielen Dank !!! – Caner

1

Etwas Ähnliches würde

/** 
* 
*/ 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.view.WindowManager; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 

/** 
* @author 
*/ 
public class TextEntryActivity extends Activity { 
    private EditText et; 

    /* 
    * (non-Javadoc) 
    * @see android.app.Activity#onCreate(android.os.Bundle) 
    */ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_text_entry); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, 
       WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
     // title 
     try { 
      String s = getIntent().getExtras().getString("title"); 
      if (s.length() > 0) { 
       this.setTitle(s); 
      } 
     } catch (Exception e) { 
     } 
     // value 

     try { 
      et = ((EditText) findViewById(R.id.txtValue)); 
      et.setText(getIntent().getExtras().getString("value")); 
     } catch (Exception e) { 
     } 
     // button 
     ((Button) findViewById(R.id.btnDone)).setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       executeDone(); 
      } 
     }); 
    } 

    /* (non-Javadoc) 
    * @see android.app.Activity#onBackPressed() 
    */ 
    @Override 
    public void onBackPressed() { 
     executeDone(); 
     super.onBackPressed(); 
    } 

    /** 
    * 
    */ 
    private void executeDone() { 
     Intent resultIntent = new Intent(); 
     resultIntent.putExtra("value", TextEntryActivity.this.et.getText().toString()); 
     setResult(Activity.RESULT_OK, resultIntent); 
     finish(); 
    } 


} 

Der Start zu tun ist:

public void launchPreferedNameEdit() { 
    Intent foo = new Intent(this, TextEntryActivity.class); 
    foo.putExtra("value", objItem.getPreferedNickname()); 
    this.startActivityForResult(foo, EDIT_PREFERED_NAME); 
} 

Sie erhalten das Ergebnis von

mit
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    switch (requestCode) { 
     case EDIT_PREFERED_NAME: 
      try { 
       String value = data.getStringExtra("value"); 
       if (value != null && value.length() > 0) { 

       } 
      } catch (Exception e) { 
      } 
      break; 
     default: 
      break; 
    } 
} 
+0

Ich könnte falsch liegen, aber ich denke, das wird überhaupt nicht für das Problem funktionieren, das ich beschrieb ? Ich habe meine Frage bearbeitet, um das Problem zu klären. – ab11

+0

Wie Sie beschrieben haben, ist das nicht möglich. Aber meine Beiträge bieten die Möglichkeit, wie Sie dies mit einer Aktivität machen können, die einen Eingabetext hat. – Pentium10

27

Ist das möglich?

Nein. In Android gibt es kein blockierendes UI-Modell. Alles ist asynchron.

UPDATE

Als Reaktion auf einige Ihrer Kommentare auf die Frage selbst, können Sie nicht eine Benutzeroberfläche von einem Hintergrund-Thread angezeigt werden soll. Wie ich in dieser Antwort geschrieben habe, gibt es in Android kein blockierendes UI-Modell. Fügen Sie Ihren Code einfach in den Button-Handler für Ihren Dialog ein, den Sie bei der Annahme des Dialogs ausführen möchten, z. B. in this sample project.

+0

Gibt es einen besonderen Grund, warum diese Antwort abgelehnt wurde? –

+2

Vielleicht ist es die Antwort, die jemand nicht hören wollte? Ich habe es ein paar Mal passiert. – blindstuff

+2

Sie können eine Benutzeroberfläche nicht direkt aus einem Hintergrundthread anzeigen, Sie können jedoch vom Hintergrundthread anfordern, dass der UI-Thread sie für Sie anzeigt. –

10

Der richtige Weg, dies zu tun, ist ein ereignisgesteuertes Programmmodell, dh "Ruf uns nicht an, wir rufen dich an".

In der einfachen Konsolenmodus-Programmierung neigt Ihr Code dazu, blockierende Eingabefunktionen aufzurufen, die erst zurückgegeben werden, wenn Sie einen Wert erhalten haben.

Viele GUI-Programmierumgebungen funktionieren anders - Ihr Code läuft normalerweise nicht, sondern wird vom Betriebssystem/Fenstermanager aufgerufen, wenn etwas von potentiellem Interesse passiert. Sie tun etwas als Antwort darauf und kehren sofort zurück - wenn Sie dies nicht tun, können Sie nichts anderes erfahren, da das Betriebssystem Sie erst kontaktieren kann, wenn Sie zurück sind. (Im Vergleich zu win32 ist es so, als ob die Nachrichtenschleife von Android implementiert wird und Sie nur den Rest des Codes schreiben, den die Nachrichtenschleife mit Ereignissen aufruft - wenn Sie nicht sofort zurückkommen, hängt die Nachrichtenschleife)

Als Ergebnis müssen Sie Ihr Konzept des Programmablaufs überdenken. Anstatt eine To-Do-Liste als eine einfache Reihe von Anweisungen zu schreiben, sollte man sie als eine Abfolge von Aktionen betrachten, die voneinander und von der Eingabe abhängen. Merken Sie sich, welche Aktion Sie gerade in einer Statusvariablen ausführen.Wenn Sie mit einem Ereignis wie einer Benutzereingabe aufgerufen werden, sehen Sie, ob dieses Ereignis bedeutet, dass es jetzt möglich ist, mit dem nächsten Schritt fortzufahren, und aktualisieren Sie Ihre Statusvariable, bevor Sie sofort zum Betriebssystem zurückkehren, um das nächste zu erhalten Veranstaltung. Wenn das Ereignis nicht Ihren Anforderungen entsprach, kehren Sie einfach zurück, ohne Ihren Status zu aktualisieren.

Wenn dieses Modell für Sie nicht funktioniert, können Sie einen Hintergrundthread der Programmlogik schreiben, der wie eine Konsole-Modus-Anwendung mit blockierender Eingabe ausgeführt wird. Aber Ihre Eingabefunktionen warten nur auf ein Flag oder etwas, um benachrichtigt zu werden, dass die Eingabe verfügbar ist. Dann aktualisieren Sie in Ihrem UInthread, auf dem Android Ereignisse liefert, die Flagge und kehren sofort zurück. Der Hintergrundthread sieht, dass sich das Flag geändert hat, um anzuzeigen, dass Daten bereitgestellt wurden, und setzt die Ausführung fort. (Etwas wie ein Android-Terminal-Emulator nimmt dies zu einem Extrem, wo die Hintergrund-Komponente ist eigentlich ein anderer Prozess - ein Konsolenmodus Linux eins, und es erhält seine Eingabe mit potenziell blockierenden I/O aus Rohren. Die Java-Komponente akzeptiert android UI-Ereignisse und stopft Zeichen in das stdin Rohr und zieht sie aus dem stdout Rohr heraus, um auf dem Schirm anzuzeigen.)

0

FALL: Meine Daten waren bereit, Prozesse nach einem Präferenzänderung Hörer Ereignis und ich musste eine Zeichenfolge vom Benutzer abgefragt hinzufügen. Es scheint nicht möglich, einen Alarmdialog zu öffnen, während das Optionsmenü geöffnet ist ... also musste ich warten. Ich warf das halb fertige Objekt in die nächste Aktivität des Arbeitsablaufs und setzte onResume(), um zu prüfen, ob sein Platzhalter! Null war. In diesem Fall habe ich den Dialog * "im Button-Handler des Dialogs beendet "*.

Da dies mein erster Beitrag ist, kann ich nicht für die oben angegebene richtige Antwort stimmen, sondern möchte jeden anderen retten, der in diese Zeit und In-Eleganz von weniger korrekten Lösungen läuft. Der Dialog ist der Ort.

0

Sie können in Bezug auf eine Zustandsmaschine denken, wo Sie, wenn Sie erstmalige Benutzereingaben erfordern, ein Flag setzen können, um "Benutzereingabe erforderlich" oder was auch immer zu markieren. Wenn Sie dann ein Ereignis verarbeiten, prüfen Sie dieses Flag und wenn gesetzt, starten Sie einen Dialog als einzige Aktion für das Ereignis und setzen das Flag zurück. Dann können Sie nach der Verarbeitung von Benutzereingaben aus dem Dialog-Event-Handler den normalerweise für den Fall vorgesehenen Code aufrufen, wenn kein Dialog benötigt wird.

0

Ich hatte Schwierigkeiten, alle oben angebotenen Lösungen zu verstehen, also habe ich meine eigene gefunden.

ich den Code, das ist wickeln soll durchgeführt werden, nachdem die Benutzereingabe in einem runnable OK'ed wird, etwa so:

Runnable rOpenFile = new Runnable() { 
     @Override 
     public void run() { 
      .... code to perform 
     } 
    } 

Dann rechts unten, dass ich den Namen der ausführbaren Funktion an den Benutzer übergeben Dialogmethode.

userInput("Open File", rOpenFile); 

Die userInput-Methode basiert wie oben beschrieben auf dem Builder für alertDialog. Wenn die Benutzereingabe Ok'ed ist, startet das beabsichtigte ausführbare Programm.

private void userInput(String sTitle, final Runnable func) { 
    AlertDialog.Builder aBuilder = new AlertDialog.Builder(this); 

    aBuilder.setTitle(sTitle); 
    final EditText input = new EditText(this); 
    input.setInputType(InputType.TYPE_CLASS_TEXT); 
    aBuilder.setView(input); 

    bDialogDone = false; 

    aBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      final String sText = input.getText().toString(); 
      sEingabe = sText; 
      func.run(); 
     } 
    }); 
    aBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      dialog.cancel(); 
      sEingabe = ""; 
     } 
    }); 

    aBuilder.show(); 
}