Динамическое обновление адаптера AutoCompleteTextView - PullRequest
36 голосов
/ 11 ноября 2011

Я хочу периодически изменять предложения, представленные AutoCompleteTextview, получая список от веб-службы RESTful, и не могу заставить его работать гладко.Я настроил жестко запрограммированный список предложений, чтобы убедиться, что он работает:

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

У меня есть TextWatcher для просмотра текста, и при изменении текста запускается неблокирующий вызов для получения нового списка.предложений - эта часть, которая получает новый список, работает нормально.Затем я хочу сбросить адаптер, например так:

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

Этот метод вызывается, но не работает - список предложений либо исчезает, либо отображаемые предложения остаются неизменными, несмотря на вызов setAdapter.

Это даже правильный подход?Я посмотрел на SimpleCursorAdapter, но не увидел, как зарегистрировать мой веб-сервис в качестве поставщика контента.(Он имеет вид http://www.blah.com/query?term=XX,, где XX - это входные данные из моего приложения, а ответ представляет собой массив строк JSON.)

Ответы [ 5 ]

39 голосов
/ 29 октября 2013

Мне не повезло с использованием adapter.notifyDataSetChanged () при динамическом добавлении и изменении данных в адаптере.В моей ситуации я выполнял асинхронный доступ к внешнему API и периодически получал список данных о завершении.

Этот код очищает адаптер и добавляет новые данные, как вы ожидаете.Однако мне пришлось вызвать метод getFilter (). Filter, чтобы заставить данные отображаться.Кроме того, мне пришлось явно фильтровать на основе текущего текста в AutocompleteTextView, потому что мой вызов API был асинхронным.

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);
23 голосов
/ 20 июня 2013

Был довольно хороший учебник по этой теме с использованием удаленных данных в Google Map API для заполнения AutoCompleteTextView здесь .

Если вам нужна кэшированная версия, я извлек ее из здесь .Исходное руководство было удалено, но, по сути, вам нужно написать ArrayAdapter с настраиваемым фильтром, аналогичным показанному ниже, и назначить его в AutoCompleteTextView.

Примечание. Необходимо реализовать метод autocomplete (), который выполняет любую операцию, необходимую для синхронной выборки и возврата элементов автозаполнения.Поскольку фильтр вызывается в фоновом потоке, он не будет блокировать основной поток пользовательского интерфейса.

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;
}
}
18 голосов
/ 16 ноября 2011

Вот как я обновляю свой 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);

Теперь, конечно, это статично и не имеет отношения к беспроводным предложениям, но я также могу предложить вам уведомить адаптердля изменений после назначения его в AutoCompleteTextView:

adapter.notifyDataSetChanged();   

Надеюсь, это поможет.

-serkan

2 голосов
/ 12 августа 2018

Лучшее решение, которое я нашел для обновления адаптера:

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

Как это работает:

Мы устанавливаем текст autoCompleteTextView с его текущим текстом, поэтому адаптер уведомляет об изменении данных и обновляет содержимое listViews.

Но с помощью этого трюка курсор перемещаетсяк началу редактирования текста.поэтому мы используем autocomplete.setSelection(text.length()) для перемещения курсора до конца.

Работает как шарм!

Редактировать:

Также вы должны использовать методы clear(), add() и remove() непосредственно на вашем ArrayAdapter вместо ArrayList.

2 голосов
/ 30 января 2015

Поскольку я не могу добавить комментарий, я даю новый ответ Нет необходимости очищать адаптер или вызывать adapter.getFilter (). Filter (...) ... Чтобы динамически обновить адаптер AutoCompleteTextView, просто добавьте новый элемент в адаптер и снова установите adapter. Для примера, приведенного в исходном вопросе, я попробовал следующее, и оно работает (код ниже не показывает начальную настройку адаптера, поскольку здесь приведены несколько ответов. Это просто показывает динамическое обновление адаптера). Обновление адаптера может быть рядом с кодом, который обновляет список, связанный с 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...