eConti - программирование в вопросах и ответах

Android: как асинхронно получать поисковые подсказки из Интернета?

Я создал активность для поиска. Теперь я хочу добавить поисковые предложения, взятые из веб-службы. Я хочу получать эти предложения асинхронно. Согласно Добавление пользовательских предложений, мне нужно переопределить метод запроса, сделайте мое предложение выполнить поиск, создать собственный MatrixCursor и вернуть его. но это проблема, мой запрос на получение предложения является асинхронным. поэтому, когда результат возвращается из сети, он выходит за рамки метода запроса.


  • под предложением поиска вы имеете в виду AutoCompleteTextView ?? 23.07.2012
  • Нет. Я использую диалоговое окно поиска Android. как описано в документации: при использовании диалогового окна поиска Android или виджета поиска вы можете предоставлять настраиваемые поисковые предложения, созданные на основе данных в вашем приложении. то, что я пытаюсь сделать, это получить это предложение от сервера, а не от БД. 24.07.2012

Ответы:


1

Вот пример 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;
}
04.05.2015
  • Не могли бы вы объяснить свою реализацию лучше? Например, что делает метод doSearch(suggestions.get(position))? Благодарить 12.04.2016
  • Работал на меня. Метод doSearch — это просто метод, который делает то, что вы хотите сделать, когда пользователь нажимает на предложение поиска. 19.09.2018

  • 2

    Похоже, что запрос к поставщику содержимого предложений не выполняется в потоке пользовательского интерфейса, согласно этому ответу: https://stackoverflow.com/a/12895381/621690 . Если вы можете изменить свой http-запрос, вы можете просто вызвать его блокировку внутри метода запроса. Может помочь прослушивание прерываний или других сигналов (возможно, пользовательских), чтобы остановить ненужные запросы.

    Другой вариант — если вы не хотите изменять какие-либо классы запросов, которые уже являются асинхронными (например, если вы используете Robospice), — должен просто вернуть ссылку MatrixCursor и заполнить ее позже. Класс AbstractCursor уже реализует шаблон Observer и отправляет уведомления в случае изменений. Если поисковая система слушает, она должна обрабатывать любые изменения в данных. Мне еще предстоит реализовать это самому, поэтому я не могу подтвердить, что это сработает так хорошо, как я себе это представляю. (Посмотрите на источник CursorLoader для большего вдохновения.)

    И вообще, разве не в этом весь смысл курсора? В противном случае мы могли бы просто вернуть список с данными.

    ОБНОВЛЕНИЕ: для меня использование MatrixCursor не сработало. Вместо этого я реализовал два других решения:

    1. Использование AutoCompleteTextField в сочетании с настраиваемым подклассом ArrayAdapter, который сам использует настраиваемый подкласс Filter. Метод Filter#performFiltering() (который я переопределяю синхронным вызовом удаленной службы) вызывается асинхронно, и поток пользовательского интерфейса не блокируется.
    2. Использование 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);
              }
          }
      }
      

    Этот метод обеспечивает запуск уведомлений на адаптере и, следовательно, список результатов поиска.

    17.10.2013
  • Определенно правильная мысль. Я пытаюсь сделать именно это, но похоже, что поисковые подсказки Android не слушают изменения курсора. :/ В частности, я звоню ContentResolver.notifyChange(), но не вижу, чтобы SuggestionAdapter вызывает registerContentObserver(). Любые идеи? Я что-то упустил? 05.11.2013
  • Это звучало как правильная идея, но она не сработала (по крайней мере, не для меня). Обновил мой ответ моими текущими решениями. 05.11.2013
  • Спасибо за обновления! эти текущие решения имеют смысл для результатов поиска. я все еще ищу способ обновить поиск предложения после того, как они были возвращены. я подозреваю, что может не быть способа... но если вы знаете один, пожалуйста, дайте нам знать! 06.11.2013

  • 3

    Самое близкое, что я нашел для решения этой проблемы, — это использовать ContentProvider и выполнить сетевой запрос по методу Query вашего провайдера (даже если это противоречит лучшим практикам), в результате вы можете создать MatrixCursor как показано здесь и здесь.

    Я все еще ищу другие варианты, такие как использование SyncAdapter, которое кажется чрезмерным для того, чтобы просто показать предложения, которые больше нигде не используются.

    Другой вариант, который я использовал для асинхронного выполнения, — это использовать AutoCompleteTextView, таким образом вы можете создать собственный адаптер, в котором вы можете реализовать функцию getFilter, как показано в этот ответ.

    27.07.2012
  • Создание MatrixCursor, как показано в примерах, не решает проблему, так как я хочу получать предложения асинхронно с сервера. 30.07.2012
  • @toko, пожалуйста, посмотрите мой ответ, я добавил еще один вариант, тот, который я выбрал в конце, который не будет блокировать ваш поток пользовательского интерфейса, пока вы получаете данные из Интернета. 30.07.2012
  • проблема в том, что я не использую AutoCompleteTextView. Я использую диалог интерфейса поиска: developer.android.com/guide/topics /search/search-dialog.html 01.08.2012
  • @toko хорошо, если вам нужно придерживаться диалогового окна поиска, вам нужно сделать этот вызов на сервер не асинхронным, поместите свой сетевой запрос в функцию запроса вашего провайдера ... что противоречит рекомендациям, хотя в этом случае у вас может не быть другого варианта. 01.08.2012
  • Новые материалы

    ИИ для общего блага, часть вторая
    В нашем последнем блоге мы исследовали возможности ИИ для общего блага, указав на несколько инициатив по поиску действенных решений для продвижения справедливых и беспристрастных систем ИИ. По..

    Время расцвета закончилось
    Большую часть своей карьеры в индустрии программного обеспечения программисты работали с головой в песок. Успех в отрасли требует навыков презентации и обучения других. Ценность улучшенных..

    Будущее сельского хозяйства: новый уровень производительности с современными технологиями
    По мере роста населения мира растет и спрос на продукты питания. Фермеры сталкиваются с растущим давлением необходимости повышать урожайность и максимизировать производительность, манипулируя..

    Состояние совместной фильтрации в 2022 году, часть 1
    ResBeMF: Улучшение прогнозируемого охвата совместной фильтрации на основе классификации (arXiv) Автор: Анхель Гонсалес-Прието , Авраам Гутьеррес , Фернандо Ортега , Рауль Лара-Кабрера..

    Зачем изучать PYTHON в 2022 году !
    Python — востребованный, доступный язык программирования с активным, постоянно растущим сообществом пользователей. Для тех, кто хочет сменить профессию в мире технологий с помощью..

    Решение капч с помощью Puppeteer
    Это руководство предназначено для текстовых кодов, а не для reCAPTCHA Google (см. конец этого сообщения). Требования: Антикапча или любой другой сервис по разгадыванию капчи. Модуль..

    7 встроенных библиотек Python, которые необходимо знать
    7 встроенных библиотек Python, которые необходимо знать Стандартная библиотека Python значительно упрощает жизнь программистов, предоставляя широкий набор функций. Мы выбираем несколько..