Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Это входит в ваш метод ContentProvider query():

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;

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

Ответ 2

Вот пример 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;
}

Ответ 3

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

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

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

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

    }

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

  • В моем однопользовательском классе приложения я определяю статическую переменную, которая используется как временные данные вместе со своими методами getter/setter:

    private static HashMap transientData = new HashMap();

    public static Object getTransientData (String objectName) {

    return transientData.get(objectName);
    

    }

    public static void setTransientData (String objectName, объект Object) {

    transientData.put(objectName, object);
    

    }

  • теперь логика: В этой операции перед вызовом getSupportLoaderManager(). InitLoader (...) Я назвал MyApplication.setTransientData( "requestor", this):

В моем классе поставщика контента, в запросе volley onResponse callback, я сделал следующее:

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

  ...

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

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

}

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

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