2012-07-23 5 views
9

私は検索可能なアクティビティを作成しました。今、私はWebサービスから取得された検索提案を追加したい。私はそれらの提案を非同期的に取得したい。 Adding Custom Suggestionsによると、私はクエリメソッドをオーバーライドする必要があります、私の提案の検索を行い、自分のMatrixCursorを構築し、それを返します。しかし、これは問題です、私の提案を得るための私の要求は非同期的なものです。したがって、結果がクエリメソッドのスコープの外側からネットに戻ったとき。Android:ウェブから非同期で検索候補を取得するにはどうすればよいですか?

+0

検索の提案によって、あなたがAutoCompleteTextViewを意味ですか? –

+1

いいえAndroidの検索ダイアログを使用しています。 Androidの検索ダイアログや検索ウィジェットを使用する場合、アプリケーションのデータから作成されたカスタム検索候補を提供することができます。私がしようとしているのは、DBからではなく、サーバーからの提案を得ることです。 – toko

答えて

0

私がこれを解決するために見つけた最も近いことは、ContentProviderを使用して、それはherehereです。

私はまだSyncAdapterのような他のオプションを探していますが、他の場所では使用されていない候補を表示するだけの理由で圧倒的と思われます。

これを非同期的に行うための別のオプションは、this answerのようにgetFilter関数を実装できるカスタムアダプタを作成できるように、AutoCompleteTextViewを使用することです。

+0

MatrixCursorを例で示したように作成しても、サーバーから非同期で提案を取得したいので問題は解決しません。 – toko

+0

@toko私の回答を参照してください編集、別のオプションを追加しました。これは、最後に取ったものです。ウェブからデータを取得している間はUIスレッドをブロックしません。 –

+0

問題は私がAutoCompleteTextViewを使用していないことです。検索インターフェースダイアログを使用しています:http://developer.android.com/guide/topics/search/search-dialog.html – toko

1

提案のコンテンツプロバイダへのリクエストは、とにかく、この回答:https://stackoverflow.com/a/12895381/621690によると、UIスレッドで実行されていないようです。 httpリクエストを変更できる場合は、単にクエリメソッド内でそのリクエストをブロックすることができます。中断やその他のシグナル(カスタムのもの)を聞いて不要なリクエストを止めるのに役立つかもしれません。

もう1つのオプション - 既に非同期のリクエストクラス(Robospiceを使用している場合など)を変更しない場合は、MatrixCursor参照を返して後で入力する必要があります。 AbstractCursorクラスは既にObserverパターンを実装しており、変更があった場合に通知を送信します。検索システムがリスニングしている場合は、データの変更を処理する必要があります。私はまだそれを実装する必要があるので、私はそれがうまくいくかどうかを確認することはできません。 (より多くのインスピレーションのためにCursorLoaderのソースを見てください)

とにかく、カーソルの全体のポイントではありませんか?それ以外の場合は、単にデータを含むリストを返すことができます。

更新: 私の場合、MatrixCursorを使用してもうまくいきませんでした。自身がフィルターのカスタムサブクラスを使用していますArrayAdapterのカスタムサブクラスとの組み合わせでAutoCompleteTextFieldを使用して

  1. :代わりに、私は2つの他のソリューションを実装しています。メソッドFilter#performFiltering()(リモートサービスへの同期呼び出しでオーバーライドする)は非同期に呼び出され、UIスレッドはブロックされません。
  2. SearchableActivityとカスタムArrayAdapter(カスタムフィルタなし)でのSearchWidgetの使用。検索意図が来ると、リモート要求は(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

+0

それは正しい考えのように聞こえたが、うまくいかなかった(少なくとも私のためではない)。現在のソリューションで私の答えを更新しました。更新のための – Risadinha

+0

ありがとうございます!現在のソリューションは検索結果に意味があります。私はまだ彼らが戻ってきた後、[search _suggestions_](http://developer.android.com/guide/topics/search/adding-custom-suggestions.html)を更新する方法を探しています。私は方法がないかもしれないと思う...しかしあなたが1つを知っているなら、私たちに知らせてください! – ryan

0

は(私が改修を使用)、ネットワークサービスからの提案を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; 
} 
+2

あなたの実装をより良く説明できますか?同様に、メソッド 'doSearch(suggestions.get(position))'はどうしますか?感謝 –