2012-07-23 57 views
9

我創建了一個可搜索的活動。現在,我想添加來自Web服務的搜索建議。我想要異步獲取這些建議。根據Adding Custom Suggestions我需要重寫查詢方法,做我的建議搜索,建立我自己的MatrixCursor並返回它。但這是問題,我的建議請求是異步的。所以當結果從網絡返回時,它不在查詢方法的範圍之內。Android:如何從網上異步獲取搜索建議?

+0

通過搜索建議你的意思是AutoCompleteTextView? – 2012-07-23 11:52:48

+1

不,我正在使用Android搜索對話框。如文檔中所述:「使用Android搜索對話框或搜索小部件時,您可以提供自定義搜索建議,這些建議是根據應用程序中的數據創建的。」我想要做的是從服務器獲取這些建議,而不是從數據庫中獲得這些建議。 – toko 2012-07-24 05:10:47

回答

0

我發現解決這個問題的最接近的方法是使用ContentProvider並對提供者的Query方法執行網絡請求(即使這違背了最佳實踐),結果您可以創建一個MatrixCursor因爲它顯示herehere

我仍在尋找其他選項,如使用SyncAdapter,這似乎壓倒性的目的只是顯示其他地方不使用的建議。

另一種選擇是我使用一個AutoCompleteTextView來創建一個自定義適配器,您可以在其中實現getFilter函數,如this answer所示。

+0

在示例中顯示的創建MatrixCursor並不能解決問題,因爲我想從服務器異步獲取建議。 – toko 2012-07-30 10:11:18

+0

@toko請參閱我的答案編輯,我添加了另一個選項,這是我在最後拿到的選項,它不會在從Web獲取數據時阻塞您的UI線程。 – 2012-07-30 14:29:06

+0

問題是我沒有使用AutoCompleteTextView。我正在使用搜索界面對話框:http://developer.android.com/guide/topics/search/search-dialog.html – toko 2012-08-01 11:04:07

1

似乎對建議內容提供者的請求不是在UI線程上運行,無論如何,根據這個答案:https://stackoverflow.com/a/12895381/621690。 如果你可以改變你的http請求,你可以簡單地在查詢方法中調用它。可能有助於聽取中斷或其他信號(可能是定製的)以阻止不必要的請求。

另一種選擇 - 如果你不想改變任何已經異步的請求類(就像你正在使用Robospice一樣) - 應該是返回MatrixCursor引用並在以後填充它。 AbstractCursor類已經實現了Observer模式,並在發生更改時發送通知。如果搜索系統正在監聽,它應該處理數據中的任何更改。我還沒有自己實現,所以我不能確認它會像我描繪的那樣很好地工作。 (看看CursorLoader的靈感來源。)

而且,無論如何,不​​是光標的整個點?否則,我們可以簡單地用數據返回一個列表。

更新: 對我而言,使用MatrixCursor無法解決問題。相反,我已經實現了其他兩種解決方案:

  1. 結合使用的AutoCompleteTextField與ArrayAdapter的自定義子類,本身使用過濾器的自定義子類。方法Filter#performFiltering()(我通過對遠程服務的同步調用重寫)被異步調用,並且UI線程未被阻止。
  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); 
         } 
        } 
    } 
    

這種方法需要觸發的護理適配器上的通知以及搜索結果列表中的通知。

+0

絕對是正確的想法。我試圖做到這一點,但它看起來像Android的搜索建議不聽指針的變化。 :/具體來說,我打電話給'ContentResolver.notifyChange()',但我沒有看到Android的['SuggestionAdapter'](https://android.googlesource.com/platform/frameworks/base/+/jb- release/core/java/android/widget/SuggestionsAdapter.java)調用'registerContentObserver()'。有任何想法嗎?我錯過了什麼? – ryan 2013-11-05 01:50:30

+0

這聽起來像是正確的想法,但它沒有奏效(至少不適合我)。用我目前的解決方案更新了我的答案 – Risadinha 2013-11-05 13:12:00

+0

感謝您的更新!那些當前的解決方案對搜索結果有意義。儘管如此,我仍然在尋找一種更新[search _suggestions_](http://developer.android.com/guide/topics/search/adding-custom-suggestions.html)的方法。我懷疑可能沒有辦法......但如果你知道的話,請讓我們知道! – ryan 2013-11-05 21:23:09

0

下面是搜索查看與建議,從網絡服務(我用改裝)來了一個例子:

@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; 
} 
+2

您能否更好地解釋您的實施?比如,doSearch(suggestions.get(position))'方法是做什麼的?謝謝 – 2016-04-12 13:18:19