カスタムの検索候補を追加する

Android の検索ダイアログまたは検索ウィジェットで、最近の検索クエリに基づいて検索候補を提供できます。たとえば、ユーザーが「子犬」をクエリした場合、同じクエリを再度入力すると、そのクエリが候補として表示されます。図 1 は、最近のクエリの候補が表示された検索ダイアログの例を示しています。

始める前に、基本的な検索用の検索ダイアログまたは検索ウィジェットをアプリケーションに実装します。方法については、検索インターフェースを作成するをご覧ください。

基本情報

図 1. 最近のクエリの候補が表示された検索ダイアログのスクリーンショット。

最近のクエリに基づく候補は、保存済みの検索条件です。ユーザーが候補を選択すると、検索可能なアクティビティは、検索可能なアクティビティがすでに処理している検索クエリとして、その候補を含む ACTION_SEARCH インテントを受け取ります。

最近のクエリに基づく候補を表示するには、以下の操作を行う必要があります。

  • 検索可能なアクティビティを実装します。
  • SearchRecentSuggestionsProvider を拡張するコンテンツ プロバイダを作成し、アプリ マニフェストで宣言します。
  • 検索候補を提供するコンテンツ プロバイダに関する情報を使用して、検索可能な構成を変更します。
  • 検索が実行されるたびにコンテンツ プロバイダにクエリを保存します。

Android システムが検索ダイアログを表示するのと同様に、ダイアログまたは検索ウィジェットの下に検索候補が表示されます。システムでは、候補を取得するソースを指定します。

アクティビティが検索可能であるとシステムが判断し、検索候補を提示すると、ユーザーがクエリを入力すると、以下の処理が行われます。

  1. ユーザーが入力を始めるたびに検索クエリのテキストが取得され、候補を含むコンテンツ プロバイダに対してクエリが実行されます。
  2. コンテンツ プロバイダは、検索クエリテキストに一致するすべての候補を指す Cursor を返します。
  3. Cursor から提示される候補のリストが表示されます。

最近のクエリに基づく候補が表示された後、以下の処理が行われることがあります。

  • ユーザーが別のキーを入力するか、なんらかの方法でクエリを変更すると、上記の手順が繰り返され、候補リストが更新されます。
  • ユーザーが検索を実行すると、候補は無視され、通常の ACTION_SEARCH インテントを使用して、検索可能なアクティビティに検索が配信されます。
  • ユーザーが候補を選択すると、候補のテキストをクエリとして使用して、ACTION_SEARCH インテントが検索可能なアクティビティに配信されます。

コンテンツ プロバイダ用に拡張した SearchRecentSuggestionsProvider クラスは、上記の手順を自動的に行うため、記述するコードはほとんどありません。

コンテンツ プロバイダを作成する

最近のクエリの候補を表示するために必要なコンテンツ プロバイダは、SearchRecentSuggestionsProvider の実装です。このクラスはすべてを自動的に行います。必要なのは、1 行のコードを実行するクラス コンストラクタを作成することだけです。

たとえば、最近のクエリの候補を表示するためのコンテンツ プロバイダの完全な実装を次に示します。

Kotlin

class MySuggestionProvider : SearchRecentSuggestionsProvider() {
    init {
        setupSuggestions(AUTHORITY, MODE)
    }

    companion object {
        const val AUTHORITY = "com.example.MySuggestionProvider"
        const val MODE: Int = SearchRecentSuggestionsProvider.DATABASE_MODE_QUERIES
    }
}

Java

public class MySuggestionProvider extends SearchRecentSuggestionsProvider {
    public final static String AUTHORITY = "com.example.MySuggestionProvider";
    public final static int MODE = DATABASE_MODE_QUERIES;

    public MySuggestionProvider() {
        setupSuggestions(AUTHORITY, MODE);
    }
}

setupSuggestions() の呼び出しでは、検索権限の名前とデータベース モードが渡されます。検索権限には任意の一意の文字列を指定できますが、コンテンツ プロバイダの完全修飾名を使用することをおすすめします(パッケージ名の後にプロバイダのクラス名を続けるなど)。例: "com.example.MySuggestionProvider"

データベース モードには DATABASE_MODE_QUERIES を含める必要があります。また、必要に応じて DATABASE_MODE_2LINES を含めることができます。これにより、候補テーブルに列が追加され、各候補で 2 行目のテキストを提供できます。各候補で 2 行を指定する場合は、次の例をご覧ください。

Kotlin

const val MODE: Int = DATABASE_MODE_QUERIES or DATABASE_MODE_2LINES

Java

public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;

SearchRecentSuggestionsProvider クラスと検索可能な構成で使用するのと同じオーソリティ文字列を使用して、アプリ マニフェストでコンテンツ プロバイダを宣言します。たとえば、以下の場合です。

<application>
    <provider android:name=".MySuggestionProvider"
              android:authorities="com.example.MySuggestionProvider" />
    ...
</application>

検索可能な構成を変更する

候補プロバイダを使用するようにシステムを設定するには、検索可能な構成ファイルの <searchable> 要素に android:searchSuggestAuthority 属性と android:searchSuggestSelection 属性を追加します。たとえば、以下の場合です。

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_label"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.example.MySuggestionProvider"
    android:searchSuggestSelection=" ?" >
</searchable>

android:searchSuggestAuthority の値は、コンテンツ プロバイダで使用されるオーソリティと完全に一致するコンテンツ プロバイダの完全修飾名(上記の例の "com.example.MySuggestionProvider" など)にする必要があります。

android:searchSuggestSelection の値は、先頭にスペースが付いた 1 つの疑問符(" ?")にする必要があります。これは SQLite 選択引数のプレースホルダであり、ユーザーが入力したクエリテキストに自動的に置き換えられます。

クエリを保存

最近のクエリのコレクションにデータを入力するには、検索可能なアクティビティが受け取った各クエリを SearchRecentSuggestionsProvider に追加します。そのためには、SearchRecentSuggestions のインスタンスを作成し、検索可能なアクティビティがクエリを受け取るたびに saveRecentQuery() を呼び出します。以下に、アクティビティの onCreate() メソッド中にクエリを保存する方法の例を示します。

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

    if (Intent.ACTION_SEARCH == intent.action) {
        intent.getStringExtra(SearchManager.QUERY)?.also { query ->
            SearchRecentSuggestions(this, MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE)
                    .saveRecentQuery(query, null)
        }
    }
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent  = getIntent();

    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
        String query = intent.getStringExtra(SearchManager.QUERY);
        SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
                MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
        suggestions.saveRecentQuery(query, null);
    }
}

SearchRecentSuggestionsProvider コンストラクタには、コンテンツ プロバイダによって宣言されるものと同じ権限とデータベース モードが必要です。

saveRecentQuery() メソッドは、最初のパラメータとして検索クエリ文字列を受け取ります。また、候補の 2 行目として含める 2 番目の文字列(省略可)または null を受け取ることもできます。2 つ目のパラメータは、DATABASE_MODE_2LINES で検索候補の 2 行モードを有効にする場合にのみ使用されます。2 行モードを有効にすると、システムが一致する候補を検索するときに、クエリテキストが 2 行目と照合されます。

候補のデータを消去

ユーザーのプライバシーを保護するため、最近のクエリの候補を消去する方法をユーザーに提供してください。クエリ履歴を消去するには、clearHistory() を呼び出します。次に例を示します。

Kotlin

SearchRecentSuggestions(this, HelloSuggestionsProvider.AUTHORITY, HelloSuggestionsProvider.MODE)
        .clearHistory()

Java

SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
        HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
suggestions.clearHistory();

この操作は、[検索履歴を消去] メニュー項目、設定項目、ボタンのいずれかを選択して実行します。ユーザーが検索履歴の削除を希望していることを確認するダイアログを表示します。