2010-12-07 4 views
34

Je voudrais implémenter une méthode qui affiche une boîte de dialogue, attend que la boîte de dialogue soit fermée, puis renvoie un résultat en fonction du contenu de la boîte de dialogue. Est-ce possible?Android: attendre l'entrée de l'utilisateur à partir de la boîte de dialogue?

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

Je suis en train d'essayer de mettre en œuvre une interface qui a méthode « public String getUserInput() », où la chaîne de retour doit être récupéré par boîte de dialogue. Cela se fait facilement en Java, semble impossible dans Android?

EDIT: affichage du code de l'échantillon tel que demandé dans le commentaire

getInput() doit être appelé à partir d'un fil de fond (je l'appelle d'un AsynchTask). getInput() affiche une boîte de dialogue et les appels sont en attente. Lorsque le bouton OK est enfoncé dans la boîte de dialogue, la boîte de dialogue définit l'entrée utilisateur dans une variable membre et appelle notifier. Lorsque notify est appelé, getInput() continue et renvoie la variable membre.

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

Vous ne pouvez pas attendre l'utilisateur dans une méthode appelée sur le thread d'interface utilisateur. Vous devez donc soit basculer vers un modèle de flux de programme piloté par événement, soit l'appeler à partir d'un thread d'arrière-plan qui peut attendre qu'une méthode onWhatever() appelle le thread d'interface utilisateur en réponse à l'action de l'utilisateur. –

+0

Je ne comprends pas vraiment, pourriez-vous m'expliquer comment je l'appellerais d'un thread d'arrière-plan, puis retourner ma chaîne surWhatever()? – ab11

+0

Parce que si vous bloquiez le thread de l'interface utilisateur pour plus de 3 (?), Je pense qu'il était trois secondes, vous obtiendrez une boîte de dialogue ANR demandant si vous souhaitez fermer l'application. Ne jamais exécuter de blocage sur le fil de l'interface utilisateur dans Android. –

Répondre

11

Merci pour tous les commentaires, j'ai été capable de résoudre cela en utilisant un fil de fond avec une attente() et notifier (). Je reconnais que ce n'est pas la meilleure idée pour le paradigme donné, mais il était nécessaire de se conformer à une bibliothèque avec laquelle je travaille.

+1

pouvez-vous poster du code? – Caner

+2

mis à jour ma réponse avec un peu de code – ab11

+0

merci beaucoup! – Caner

1

Quelque chose comme ça ferait

/** 
* 
*/ 

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(); 
    } 


} 

Le lancement est:

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

Vous obtenez le résultat en utilisant

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

Je peux me tromper, mais je pense que cela ne fonctionnera pas du tout pour le problème que je décris ? J'ai édité ma question pour clarifier le problème. – ab11

+0

Comme vous l'avez décrit, ce n'est pas possible. Mais mes messages fournissent la manière dont vous pouvez le faire avec une activité qui a un texte d'entrée. – Pentium10

27

Est-ce possible?

Non. Il n'y a pas de modèle d'interface utilisateur bloquant dans Android. Tout est asynchrone.

MISE À JOUR

En réponse à certains de vos commentaires sur la question elle-même, vous ne pouvez pas afficher une interface utilisateur à partir d'un fil d'arrière-plan. Comme je l'ai écrit dans cette réponse, il n'y a pas de modèle d'interface utilisateur bloquant dans Android. Placez simplement votre code dans le gestionnaire de boutons correspondant à votre boîte de dialogue que vous souhaitez exécuter lorsque la boîte de dialogue est acceptée, par exemple en this sample project.

+0

Y a-t-il une raison particulière pour laquelle cette réponse a été rejetée? –

+2

Peut-être que c'est la réponse que quelqu'un ne voulait pas entendre? Je l'ai fait se produire plusieurs fois. – blindstuff

+2

Vous ne pouvez pas afficher directement une interface utilisateur à partir d'un thread d'arrière-plan, mais vous pouvez demander au thread d'arrière-plan que le thread d'interface utilisateur l'affiche pour vous. –

10

La meilleure façon d'y parvenir est un modèle de programme axé sur les événements, c.-à-d. «Ne nous appelez pas, nous vous appellerons».

Dans la programmation en mode console simple, votre code a tendance à appeler des fonctions d'entrée bloquantes, qui ne sont renvoyées qu'une fois que vous avez obtenu une valeur.

De nombreux environnements de programmation gui fonctionnent différemment: votre code ne s'exécute pas normalement, mais il est appelé par le système d'exploitation/gestionnaire de fenêtres lorsqu'un événement potentiellement intéressant se produit. Vous faites quelque chose en réponse à cela et retournez rapidement - si vous ne le faites pas, vous ne pouvez pas être averti de quoi que ce soit d'autre puisque l'OS n'a aucun moyen de vous contacter jusqu'à votre retour. (Par rapport à win32, c'est comme si la boucle de messages était implémentée par Android, et que vous n'écriviez que le reste du code que la boucle de messages appelle avec les événements - si vous ne revenez pas rapidement, la boucle de messages se bloque). Par conséquent, vous devez repenser votre concept de flux de programme. Au lieu d'écrire une liste de choses à faire sous la forme d'une simple série d'énoncés, considérez-la comme une séquence d'actions qui dépendent l'une de l'autre et en entrée. Rappelez-vous quelle action vous êtes actuellement dans une variable d'état.Lorsque vous êtes appelé avec un événement tel que l'entrée utilisateur, voir si cet événement signifie qu'il est maintenant possible de passer à l'étape suivante, et si c'est le cas, mettez à jour votre variable d'état avant de revenir rapidement au système d'exploitation. un événement. Si l'événement n'était pas ce dont vous aviez besoin, alors revenez simplement sans mettre à jour votre état.

Si ce modèle ne fonctionne pas pour vous, vous pouvez écrire un fil d'arrière-plan de logique de programme qui s'exécute comme une application en mode console à l'aide d'une entrée bloquante. Mais vos fonctions d'entrée vont simplement attendre sur un drapeau ou quelque chose pour être averti que l'entrée est disponible. Ensuite, sur votre fil d'interface utilisateur où Android fournit des événements, vous mettez à jour le drapeau et retournez rapidement. Le thread d'arrière-plan voit l'indicateur a changé pour indiquer que les données ont été fournies et continue l'exécution. (Quelque chose comme un émulateur de terminal Android prend cela à un extrême, où le composant de fond est en fait un autre processus - un mode console linux, et il obtient son entrée en utilisant des E/S potentiellement bloquant des pipes. remballe les caractères dans le tuyau Stdin et les sort du tuyau stdout pour les afficher sur l'écran.)

0

CAS: Mes données étaient prêtes à être traitées après un événement d'écoute de changement de préférence et j'avais besoin d'ajouter une chaîne interrogée par l'utilisateur. Il ne semble pas possible de faire apparaître une boîte de dialogue d'alerte lorsque le menu des options est ouvert ... donc j'ai dû attendre. J'ai jeté l'objet à moitié complet dans l'activité suivante dans le flux de travail et mis son onResume() pour vérifier si son espace réservé était! Null auquel cas j'ai ouvert la boîte de dialogue et terminé l'objet * "dans le gestionnaire de boutons de la boîte de dialogue "*.

Puisqu'il s'agit de mon premier article, je ne peux pas voter pour la réponse correcte donnée ci-dessus, mais je veux sauver quelqu'un d'autre qui y court le temps et l'élégance de solutions moins correctes. Le dialogue est l'endroit.

0

Vous pouvez penser en termes de machine à états où si vous avez besoin d'une première saisie par l'utilisateur, vous pouvez avoir un drapeau pour marquer "l'entrée de l'utilisateur nécessaire" ou quoi que ce soit. Ensuite, lors du traitement d'un événement, vous vérifiez ce drapeau et si vous le définissez, vous lancez une boîte de dialogue comme seule action pour l'événement et annulez le drapeau. Ensuite, à partir du gestionnaire d'événements de boîte de dialogue après avoir manipulé l'entrée utilisateur, vous pouvez appeler le code normalement prévu pour le cas lorsqu'une boîte de dialogue n'est pas nécessaire.

0

J'ai eu du mal à comprendre toutes les solutions proposées ci-dessus jusqu'à présent, j'ai donc trouvé la mienne.

J'enveloppe thats de code supposé être effectué après l'entrée utilisateur est OK'ed dans un runnable, comme ceci:

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

Puis juste en dessous que je passe le nom de la fonction runnable à l'utilisateur méthode de dialogue.

userInput("Open File", rOpenFile); 

La méthode userInput est basée sur le générateur alertDialog comme décrit ci-dessus. Lorsque l'entrée de l'utilisateur est OK, il démarre le runnable prévu.

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(); 
} 
Questions connexes