web-dev-qa-db-fra.com

Mise à jour dynamique d'un adaptateur AutoCompleteTextView

Je souhaite modifier périodiquement les suggestions émises par AutoCompleteTextview en obtenant la liste à partir d'un service Web RESTful. Je n'arrive pas à le faire fonctionner correctement. J'ai mis en place une liste de suggestions codées en dur pour s'assurer que cela fonctionne:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, new String[] {"Hi", "Ho"});
speciesName.setAdapter(adapter);//my autocomplete tv

J'ai un TextWatcher sur le textview et lorsque le texte change, un appel non bloquant est lancé pour obtenir une nouvelle liste de suggestions - cette partie qui obtient une nouvelle liste fonctionne correctement. Ensuite, je veux réinitialiser l'adaptateur, comme suit:

public void setOptionsAndUpdate(String[] options) {
    Log.d(TAG, "setting options");
    //speciesName.setAdapter((ArrayAdapter<String>)null);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, options);
    speciesName.setAdapter(adapter);
}

Cette méthode est appelée mais ne fonctionne pas - la liste des suggestions disparaît ou les suggestions affichées restent inchangées malgré l'appel à setAdapter.

Est-ce même la bonne approche? J'ai consulté SimpleCursorAdapter mais je ne voyais pas comment enregistrer mon service Web en tant que fournisseur de contenu. (Il se présente sous la forme http://www.blah.com/query?term=XX , où XX correspond à l'entrée de mon application et où la réponse est un tableau JSON de chaînes.)

32
jaybee

Voici comment mettre à jour mon AutoCompleteTextView:

String[] data = terms.toArray(new String[terms.size()]);  // terms is a List<String>
ArrayAdapter<?> adapter = new ArrayAdapter<Object>(activity, Android.R.layout.simple_dropdown_item_1line, data);
keywordField.setAdapter(adapter);  // keywordField is a AutoCompleteTextView
if(terms.size() < 40) keywordField.setThreshold(1); 
else keywordField.setThreshold(2);

Maintenant, bien sûr, ceci est statique et ne traite pas de suggestions par voie aérienne, mais je peux également vous suggérer d'informer l'adaptateur des modifications après l'avoir affectée à AutoCompleteTextView:

adapter.notifyDataSetChanged();   

J'espère que cela t'aides.

-Serkan 

17
serkanozel

Je n'ai pas eu de chance en utilisant adapter.notifyDataSetChanged () lors de l'ajout et de la modification dynamiques des données dans l'adaptateur. Dans ma situation, je frappais une api externe de manière asynchrone et obtenais une liste de données d'achèvement périodiquement. 

Ce code efface l'adaptateur et ajoute les nouvelles données comme prévu. Cependant, j'ai dû appeler la méthode getFilter (). Filter pour forcer l'affichage des données. De plus, je devais filtrer explicitement en fonction du texte actuel dans AutocompleteTextView car mon appel à l'API était asynchrone.

adapter.clear();
for (Map<String, String> map : completions) {
     adapter.add(map.get("name"));
}

//Force the adapter to filter itself, necessary to show new data.
//Filter based on the current text because api call is asynchronous. 
adapter.getFilter().filter(autocompleteTextView.getText(), null);
33
GLee

Il existait un très bon didacticiel sur ce sujet, qui utilisait des données distantes dans l'API Google Map pour remplir un fichier AutoCompleteTextView ici .

Si vous avez besoin d'une version en cache, je l'ai extraite de here . Le tutoriel d'origine a été supprimé, mais vous devez essentiellement écrire un ArrayAdapter avec un filtre personnalisé similaire à celui présenté ci-dessous et l'assigner. à votre AutoCompleteTextView. 

Remarque: vous devez implémenter une méthode autocomplete () qui effectue l'opération requise pour extraire et renvoyer de manière synchrone les éléments de l'auto-complétion. Comme le filtre est appelé dans un thread en arrière-plan, cela ne bloque pas le thread principal de l'interface utilisateur.

private class PlacesAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {
private ArrayList<String> resultList;

public PlacesAutoCompleteAdapter(Context context, int textViewResourceId) {
    super(context, textViewResourceId);
}

@Override
public int getCount() {
    return resultList.size();
}

@Override
public String getItem(int index) {
    return resultList.get(index);
}

@Override
public Filter getFilter() {
    Filter filter = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults filterResults = new FilterResults();
            if (constraint != null) {
                // Retrieve the autocomplete results.
                resultList = autocomplete(constraint.toString());

                // Assign the data to the FilterResults
                filterResults.values = resultList;
                filterResults.count = resultList.size();
            }
            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            if (results != null && results.count > 0) {
                notifyDataSetChanged();
            }
            else {
                notifyDataSetInvalidated();
            }
        }};
    return filter;
}
}
22
user937783

Étant donné que je ne peux pas ajouter de commentaire, je donne une nouvelle réponse Il n'est pas nécessaire d'effacer l'adaptateur ou d'appeler adapter.getFilter (). Filter (...) ... Pour mettre à jour de manière dynamique un adaptateur AutoCompleteTextView, ajoutez simplement le nouvel élément à l’adaptateur et setAdapter à nouveau. Pour l'exemple donné dans la question initiale, j'ai essayé ce qui suit et cela fonctionne (le code ci-dessous n'indique pas le réglage initial de l'adaptateur, car plusieurs réponses le couvrent. Cela montre simplement la mise à jour de l'adaptateur de manière dynamique). La mise à jour de l'adaptateur peut accompagner le code mettant à jour la liste associée à ArrayAdapter. 

    adapter.add(String newSuggestion); // this goes inside a loop for adding multiple suggestions
    speciesName.setAdapter(adapter) ; // speciesName is an AutoCompleteTextView as given in the original question.
2
sri_s

La meilleure solution que j'ai trouvée pour mettre à jour l'adaptateur:

Editable text = autocomplete.getText();
autocomplete.setText(text);
autocomplete.setSelection(text.length());

Comment ça marche:

Nous définissons le texte de autoCompleteTextView avec le texte actuel, de sorte que l'adaptateur informe que les données sont modifiées et met à jour le contenu de listViews.

Mais par cette astuce, le curseur se place au début de edittext. Nous utilisons donc autocomplete.setSelection(text.length()) pour déplacer le curseur à la fin.

Fonctionne comme un charme!

Modifier:

Vous devez également utiliser les méthodes clear(), add() et remove() directement sur votre ArrayAdapter au lieu de votre ArrayList

0
Nobody8