Поиск предложений с сетевого ресурса в поле быстрого поиска - PullRequest
16 голосов
/ 24 ноября 2010

Я строю поиск в приложении, и мне нужен способ поместить предложения, полученные с моего сервера в виде JSON-массива, в список предложений, который отображается под окном быстрого поиска.

Есть ли простой способ заставить окно быстрого поиска читать такие ресурсы?

В настоящее время я пытаюсь использовать ContentProvider, но методы интерфейса четко указывают на то, что предполагается запрашивать базу данных для получения предложений. Я думаю, что использование ContentProvider является правильным способом, если вы ищете данные, которые хранятся в приложении. Однако я не уверен, что это правильный путь, если вам нужно запросить сетевой ресурс.

Для меня нет смысла сохранять предложения, которые я получаю из сети, в локальную базу данных, так как предложения и их частота обращений будут время от времени меняться.

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

Ответы [ 3 ]

11 голосов
/ 04 мая 2015

Вот пример 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;
}
11 голосов
/ 24 ноября 2010

Нашел решение на developer.android.com:

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

Это относится к методу query () вашего ContentProvider:

String[] columns = {
   BaseColumns._ID, 
   SearchManager.SUGGEST_COLUMN_TEXT_1, 
   SearchManager.SUGGEST_COLUMN_INTENT_DATA
};

MatrixCursor cursor = new MatrixCursor(columns);

for (int i = 0; i < arr.length(); i++)
{
  String[] tmp = {Integer.toString(i), arr.getString(i), arr.getString(i)};
  cursor.addRow(tmp);
}
return cursor;

Курсор используется в поле быстрого поиска для заполнения списка предложений.

0 голосов
/ 30 апреля 2016

Не знаю, нужно ли это людям.На всякий случай, для будущих искателей.У меня была проблема с предложениями моего SearchView, которые не появлялись.Обыскав вокруг, я нашел решение для этого.Я использовал Volley для своего класса провайдера контента (чтобы получить предложения от веб-API), который, казалось, не вписывался в структуру провайдера контента Android.Я также обнаружил, что мой поставщик контента работает в потоке пользовательского интерфейса.Поэтому, если я использовал в нем Волейное будущее синхронно, он замедлял (блокировал) пользовательский интерфейс до возвращения запроса (тайм-аут).Кроме того, я нашел в Интернете информацию о том, что запрос Volley Future должен выполняться в другом потоке, например в асинхронной задаче, чтобы он работал хорошо.Таким образом, это не решило мою проблему, потому что, если бы мне пришлось использовать его (в асинхронной задаче), я бы вместо этого использовал обычный (асинхронный) запрос Волли (который я использовал тогда).Я сделал следующее:

  1. В моем подклассе ContentProvider я определяю интерфейс слушателя:

    открытый интерфейс ResultListener {

      void onProviderResult(Cursor mCursor);
    
      void onProviderError(String errorMsg);
    

    }

  2. В своей деятельности (которая реализовала LoaderCallbacks) я реализовал также интерфейс выше.

  3. В моем классе приложения-одиночки я определяю статическую переменную, котораяиспользуется в качестве переходных данных вместе с методами получения / установки:

    закрытая статическая HashMap transientData = new HashMap ();

    открытая статическая Object getTransientData (String objectName) {

    return transientData.get(objectName);
    

    }

    public static void setTransientData (String objectName, Object object) {

    transientData.put(objectName, object);
    

    }

  4. теперь логика: в действииперед вызовом getSupportLoaderManager (). initLoader (...) я позвонил MyApplication.setTransientData ("requestor", это) :

в моем контентекласс провайдера, в обратном вызове onResponse запроса залпа,Я сделал это:

public void onResponse (ответ JSONArray) {

  ...

  ResultListener requestor =   (ResultListener)TheApplication.getTransientData("requestor");

  if (requestor!=null) requestor.onProviderResult(mCursor);

}

Чтобы при возврате запроса залпа вызывался метод обратного вызова запрашивающего,передавая ему курсор, заполненный данными из ответа, и в свою очередь запрашивающая сторона (действие) уведомляет адаптер курсора, вызывая: adapter.swapCursor (c);adapter.notifyDataSetChanged ();

Надеюсь, это кому-нибудь поможет.Будь благословен.

...