代码之家  ›  专栏  ›  技术社区  ›  Eric Nordvik

将网络资源中的建议搜索到快速搜索框中

  •  17
  • Eric Nordvik  · 技术社区  · 15 年前

    我正在一个应用程序中构建搜索,需要有一种方法将我从服务器获得的作为JSON数组的建议放入显示在快速搜索框下面的建议列表中。

    有没有一个简单的方法让快速搜索框读取这样的资源?

    目前我正在尝试使用ContentProvider,但是接口方法明确地表明应该查询数据库以获取建议。如果您正在搜索存储在应用程序中的数据,那么使用ContentProvider是正确的方法。不过,我不太确定,如果需要查询网络资源,这是正确的方法。

    对于我来说,将从网络中得到的建议保存到本地数据库中是没有意义的,因为这些建议及其命中率将随时间而变化。

    有人有这个问题吗?或者可以把我引向一个类似的问题?我在堆栈中找不到提到网络建议的问题。

    3 回复  |  直到 10 年前
        1
  •  12
  •   Eric Nordvik    15 年前

    在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
  •  11
  •   moondroid    11 年前

    下面是SearchView的一个示例,其中包含来自网络服务的建议(我使用了改型):

    @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
  •  0
  •   fiveloaves    10 年前

    不知道人们是否还需要这个。以防万一,为未来的搜索者。我对SearchView的建议有问题,但没有出现。在四处搜索之后,我找到了解决这个问题的方法。我在我的内容提供商类中使用了Volley(从Web API获取建议),这似乎与Android的内容提供商框架不太匹配。我还发现我的内容提供者确实在UI线程中运行。因此,如果我在其中同步使用volley的未来,它会减慢(阻塞)UI,直到请求返回(超时)。此外,我在Web上发现了一些信息,认为Volley的未来请求应该在其他线程中运行,例如在异步任务中,这样它才能正常工作。因此,它并没有解决我的问题,因为如果我不得不使用它(在异步任务中),我会首先使用volley的正常(异步)请求(这就是我当时使用的请求)。 我做的是:

    1. 在ContentProvider子类中,我定义了一个侦听器接口:

      公共接口结果侦听器{

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

      }

    2. 在我的活动(实现了loaderCallbacks)中,我也实现了上面的接口。

    3. 在我的singleton应用程序类中,我定义了一个用作瞬态数据的静态变量及其getter/setter方法:

      private static hashmap transientdata=new hashmap();

      公共静态对象getTransientData(字符串objectname){

      return transientData.get(objectName);
      

      }

      公共静态void setTransientData(string objectname,object object){

      transientData.put(objectName, object);
      

      }

    4. 现在的逻辑是: 在活动中,在呼叫之前 GetSupportLoaderManager().InitLoader(…) , 我打过电话 myapplication.setTransientData(“请求者”,this) :

    在我的内容提供商的类中,在Volley请求的onResponse回调中,我执行了以下操作:

    公共void onResponse(jsonArray响应){

      ...
    
      ResultListener requestor =   (ResultListener)TheApplication.getTransientData("requestor");
    
      if (requestor!=null) requestor.onProviderResult(mCursor);
    

    }

    这样,当Volley请求返回时,它将触发请求者的回调方法,并将由响应中的数据填充的光标传递给它,然后请求者(活动)通过调用以下命令通知光标适配器: 接头。SWAPCursor(C); adapter.notifyDataSetChanged();

    希望这能帮助别人。 祝福你。