searchableを使用する方法

Androidで検索処理を実装しようと思って、標準アプリの動作を見てみると、メニューや検索ボタン(エミュレータではF5キー)で検索機能を呼び出し、画面上部からにょろっと検索窓が出現して検索処理を実行する。というのが標準的な動作となっているようだ。Marketのアプリの中には独自の動作をしているものもあったが、とりあえず標準的な方法について調べてみた。
API Demosの中にサンプル(App>Search)があったが、使えるまでに結構、遠回りしてしまったので、今後のためにメモ。

searchableを使用するまでの手順

1./res/xml に "searchable.xml" ファイルを作成
<searchable
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
    android:hint="@string/search_hint"
    android:searchMode="showSearchLabelAsBadge"
    android:imeOptions="actionSearch"
    android:inputType="textPersonName"/>

検索窓の表示されるViewの定義
android:searchMode属性が何を意味するかがよくわからない。*1

2.AndroidManifest.xml 追加


呼出元のActivity定義

    <activity
        android:name=".SearchActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <!-- android:value には結果を表示するActivityを指定 -->
        <meta-data android:name="android.app.default_searchable"
                   android:value=".ResultActivity" />
    </activity>

android:name="android.app.default_searchable" の値の意味は不明
※ Activityタグの外側で宣言すれば、全画面から呼び出し可

結果表示先のActivity定義

    <activity
        android:name=".ResultActivity"
        android:label="@string/app_name">
        <!-- 検索BOXにて検索されたときは"Intent.ACTION_SEARCH"のIntentが飛ぶ -->
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <!-- searchable.xmlのリソース指定 -->
        <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable" />
    </activity>

※ searchable.xmlのリソース指定は結果表示のActivityで宣言でよい?

※ 検索と結果が同じ画面なら以下のように指定

    <activity
        android:name=".SearchActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <meta-data android:name="android.app.default_searchable"
                   android:value=".SearchActivity" />
        <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable" />
    </activity>

android:launchMode="singleTop" でタスクが積み重ならない

3.Activityで検索窓の呼び出し

Activityで検索窓を呼び出すには以下のメソッドを呼べばよい。
メニュー押下時に呼び出すか、F5キーで呼び出される。

Activity#onSearchRequested();
4.検索文字列取得

検索窓は入力された文字列をIntentに設定して次のActivityに送るだけなので、結果表示ActivityではIntentからその文字列を取り出して検索処理を実行する。

    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            検索処理(query);
        }
    }

検索と結果が同じ画面でandroid:launchMode="singleTop"が指定されていれば、onNewIntentメソッドが呼び出されるので、そこで検索処理を実行する

    @Override
    protected void onNewIntent(Intent intent) {
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            検索処理(query);
        }
    }

で、とりあえず動く状態。
細かい定義などについては調査中。
SuggestやVoice検索も出来るようだが、詳細不明。

※Suggest機能についてメモ
searchable.xmlにSuggest指定

    android:searchSuggestAuthority="コンテントプロバイダのUri"
    android:searchSuggestSelection=" ? "
    android:searchSuggestIntentAction="android.intent.action.SEARCH"

Suggestで表示された候補を選択したときは"Intent.ACTION_SEARCH"以外のActionも指定できる
入力履歴のSuggestは標準で"SearchRecentSuggestionsProviderクラス"がやってくれるみたい
独自のSuggestを使用する場合の注意点
Providerクラスの定義
URI_MATCHER.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 10);
Cursorのカラム名に_id, suggest_text_1,suggest_intent_queryは必須

*1:リファレンスでは、4つほど値が設定できるようだが、変化がわからない。