Я создал активность для поиска. Теперь я хочу добавить поисковые предложения, взятые из веб-службы. Я хочу получать эти предложения асинхронно. Согласно Добавление пользовательских предложений, мне нужно переопределить метод запроса, сделайте мое предложение выполнить поиск, создать собственный MatrixCursor и вернуть его. но это проблема, мой запрос на получение предложения является асинхронным. поэтому, когда результат возвращается из сети, он выходит за рамки метода запроса.
Android: как асинхронно получать поисковые подсказки из Интернета?
- под предложением поиска вы имеете в виду AutoCompleteTextView ?? 23.07.2012
- Нет. Я использую диалоговое окно поиска Android. как описано в документации: при использовании диалогового окна поиска Android или виджета поиска вы можете предоставлять настраиваемые поисковые предложения, созданные на основе данных в вашем приложении. то, что я пытаюсь сделать, это получить это предложение от сервера, а не от БД. 24.07.2012
Ответы:
Вот пример SearchView с предложениями, поступающими от сетевой службы (я использовал Retrofit):
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_search_activity, menu);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search));
final CursorAdapter suggestionAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
null,
new String[]{SearchManager.SUGGEST_COLUMN_TEXT_1},
new int[]{android.R.id.text1},
0);
final List<String> suggestions = new ArrayList<>();
searchView.setSuggestionsAdapter(suggestionAdapter);
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(int position) {
return false;
}
@Override
public boolean onSuggestionClick(int position) {
searchView.setQuery(suggestions.get(position), false);
searchView.clearFocus();
doSearch(suggestions.get(position));
return true;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
MyApp.autocompleteService.search(newText, new Callback<Autocomplete>() {
@Override
public void success(Autocomplete autocomplete, Response response) {
suggestions.clear();
suggestions.addAll(autocomplete.suggestions);
String[] columns = {
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA
};
MatrixCursor cursor = new MatrixCursor(columns);
for (int i = 0; i < autocomplete.suggestions.size(); i++) {
String[] tmp = {Integer.toString(i), autocomplete.suggestions.get(i), autocomplete.suggestions.get(i)};
cursor.addRow(tmp);
}
suggestionAdapter.swapCursor(cursor);
}
@Override
public void failure(RetrofitError error) {
Toast.makeText(SearchFoodActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
Log.w("autocompleteService", error.getMessage());
}
});
return false;
}
});
return true;
}
Похоже, что запрос к поставщику содержимого предложений не выполняется в потоке пользовательского интерфейса, согласно этому ответу: https://stackoverflow.com/a/12895381/621690 . Если вы можете изменить свой http-запрос, вы можете просто вызвать его блокировку внутри метода запроса. Может помочь прослушивание прерываний или других сигналов (возможно, пользовательских), чтобы остановить ненужные запросы.
Другой вариант — если вы не хотите изменять какие-либо классы запросов, которые уже являются асинхронными (например, если вы используете Robospice), — должен просто вернуть ссылку MatrixCursor и заполнить ее позже. Класс AbstractCursor уже реализует шаблон Observer и отправляет уведомления в случае изменений. Если поисковая система слушает, она должна обрабатывать любые изменения в данных. Мне еще предстоит реализовать это самому, поэтому я не могу подтвердить, что это сработает так хорошо, как я себе это представляю. (Посмотрите на источник CursorLoader для большего вдохновения.)
И вообще, разве не в этом весь смысл курсора? В противном случае мы могли бы просто вернуть список с данными.
ОБНОВЛЕНИЕ: для меня использование MatrixCursor не сработало. Вместо этого я реализовал два других решения:
- Использование AutoCompleteTextField в сочетании с настраиваемым подклассом ArrayAdapter, который сам использует настраиваемый подкласс Filter. Метод
Filter#performFiltering()
(который я переопределяю синхронным вызовом удаленной службы) вызывается асинхронно, и поток пользовательского интерфейса не блокируется. Использование SearchWidget с SearchableActivity и пользовательским ArrayAdapter (без пользовательского фильтра). Когда приходит цель поиска, запускается удаленный запрос (Robospice), и когда он возвращается через обратный вызов, я вызываю следующий пользовательский метод в моем подклассе
ArrayAdapter<Tag>
:public void addTags(List<Tag> items) { if (items != null && items.size() > 0) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { super.setNotifyOnChange(false); for (Tag tag : items) { super.add(tag); } super.notifyDataSetChanged(); } else { super.addAll(items); } } }
Этот метод обеспечивает запуск уведомлений на адаптере и, следовательно, список результатов поиска.
ContentResolver.notifyChange()
, но не вижу, чтобы SuggestionAdapter
вызывает registerContentObserver()
. Любые идеи? Я что-то упустил? 05.11.2013 Самое близкое, что я нашел для решения этой проблемы, — это использовать ContentProvider и выполнить сетевой запрос по методу Query
вашего провайдера (даже если это противоречит лучшим практикам), в результате вы можете создать MatrixCursor
как показано здесь и здесь.
Я все еще ищу другие варианты, такие как использование SyncAdapter
, которое кажется чрезмерным для того, чтобы просто показать предложения, которые больше нигде не используются.
Другой вариант, который я использовал для асинхронного выполнения, — это использовать AutoCompleteTextView, таким образом вы можете создать собственный адаптер, в котором вы можете реализовать функцию getFilter
, как показано в этот ответ.
doSearch(suggestions.get(position))
? Благодарить 12.04.2016