Android : SearchView に独自の検索候補を表示する
Adding Custom Suggestions | Android Developers からのメモ書き。
表示する検索候補をコントロールするために ContentProvider を実装する以外、検索履歴を表示する場合とほぼ変わりません。
- ContentProvier を実装する
- query (と onCreate)だけ実装すれば良い
- AndroidManifest.xml に provider を設定する
- searchable.xml に authority 設定する
ContentProvider の実装
- SearchView のテキストが変化するたびに query 関数が呼ばれる
- query で返す Cursor には BaseColumns._ID と SearchManager.SUGGEST_COLUMN_TEXT_1 の Columns が必須
- SUGGEST_COLUMN_TEXT_2 や SUGGEST_COLUMN_ICON_1 などが任意に追加可能
query に渡される引数は以下のとおりです。SearchView で使用する ContentProvider の場合、基本的に気にするのは selectionArgs[0] のみになります。
引数 | 値 |
---|---|
uri | content://(authority)/search_suggest_query?limit=50 |
projection | 常に null |
selection | searchable.xml で android:searchSuggestSelection に指定した値 |
selectionArgs | [0] に SearchView に入力されている文字列 |
sortOrder | 常に null |
(searchable.xml で android:searchSuggestSelection を指定していない場合、uri の方に "content://(authority)/search_suggest_query(/SearchView に入力された文字)?limit=50" という形式で検索語が入る代わりに、selectionArgs は null になる。path を分解する必要が出てくるので、android:searchSuggestSelection の使用を推奨。)
SQL を使わずに、決められた検索語から候補を絞る場合は MatrixCursor を使用して以下の様な感じに。 データの絞り込みには Guavaを利用しています。
public class MySearchSuggestionsProvider extends ContentProvider { String[] mSuggestionColumns; List<Object[]> mSuggestionItems; @Override public boolean onCreate() { // query で返すカラム。ここでは必須のみ。 mSuggestionColumns = new String[] { BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1 }; // サンプルデータの作成。後で MatrixCursor に追加するため、Object の配列。 mSuggestionItems = new ArrayList<>(); for(int i = 1; i <= 50; i++) { mSuggestionItems.add( new Object[] { i, String.valueOf(i) } ); } return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, final String[] selectionArgs, String sortOrder) { // 検索文字列がない場合は何も返さず非表示に。 if(TextUtils.isEmpty(selectionArgs[0])) { return null; } MatrixCursor matrixCursor = new MatrixCursor(mSuggestionColumns); // Guava を使用したフィルタリング Collection<Object[]> candidates = Collections2.filter(mSuggestionItems, new Predicate<Object[]>() { @Override public boolean apply(Object[] input) { return ((String)input[1]).contains(selectionArgs[0]); } }); for(Object[] candidate : candidates) { matrixCursor.addRow(candidate); } return matrixCursor; } // ...他のメソッドは return null や return 0.
AndroidManifest.xml への の登録
<application ... > <provider android:authorities="(権限文字列。基本的にパッケージ名 + ContentProvider のクラス名)" android:name="(ContentProvider クラスのパス)"/>
searchable.xml
<?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/app_name" android:hint="@string/app_name" android:searchSuggestAuthority="(権限名)" android:searchSuggestSelection=" ?" android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"> </searchable>