2011年5月19日木曜日

Android 検索窓にSuggestionを追加する

前回、Search Dialogを出すようにしたので、その検索窓にSuggestionを追加する。

過去の検索したキーワードを提示するようにする。

1. ContentProvider作成

下記クラス作成。
public class SuggestionsProvider extends SearchRecentSuggestionsProvider {
    public final static String AUTHORITY = "SuggestionsProvider";
    public final static int MODE = DATABASE_MODE_QUERIES;

    public SuggestionsProvider() {
        setupSuggestions(AUTHORITY, MODE);
    }
}
AndroidManifest.xmlのapplication内に追記。
        <provider android:name="SuggestionsProvider"
            android:authorities="SuggestionsProvider" />

2. Searchableの設定変更

searchable.xmlに追記。
    android:searchSuggestAuthority="SuggestionsProvider"
    android:searchSuggestSelection=" ?"

3. Queryの保存

queryの保存処理を追加する。
    @Override
    protected void onNewIntent(Intent intent) {
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            mText.setText(Html.fromHtml(mText.getText().toString().replaceAll(
                    "(" + query + ")", "<font color=\"red\">$1</font>")));

            // queryの保存
            SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
                    SuggestionsProvider.AUTHORITY, SuggestionsProvider.MODE);
            suggestions.saveRecentQuery(query, null);
        }
    }


以上で、Suggestionがでてくるようになりました。

クリアは下記のようにできるので、アプリから履歴消せるようにしておくと優しいかも。
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
    SuggestionsProvider.AUTHORITY, SuggestionsProvider.MODE);
suggestions.clearHistory();
Android Marketアプリの検索履歴は別のアプリ入れないと消せないので、消せなくても良いのかな。


んで、ここからは割とどうでもいい話。履歴はどこにどんな感じで保存されているか。

DATABASE_MODE_QUERIESってモードなんだからsqliteだろう。と、いうことでadb shellで見てみる。
# ls databases
suggestions.db

中を見てみるとsuggestionsテーブルがあるので、テーブル定義を確認。
# sqlite3 databases/suggestions.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
android_metadata  suggestions
sqlite> .schema suggestions
CREATE TABLE suggestions (_id INTEGER PRIMARY KEY,display1 TEXT UNIQUE ON CONFLICT REPLACE,query TEXT,date LONG);
SQLiteだと「UNIQUE ON CONFLICT REPLACE」なんて定義もできるのか。MySQLにはなかった。と思う。コンフリクトした場合は、replace(delete+insert)なので新しい_idが発行される。

suggestionは「order by _id desc」で出してるだけっぽいな。文字が入力されてる場合は、likeを条件につけるくらいか。
sqlite> select _id, display1 from suggestions order by _id desc;                                                               
8|system
7|search 
6|activity

# 「system」「activity」「application」の順に検索。

sqlite> select _id, query from suggestions order by _id desc;
11|application 
10|activity
9|system
7|search 
うむ、結果は同じ。