最近のクエリに基づく候補の追加

Android 検索ダイアログまたは検索ウィジェットを使用すると、最近の検索クエリに基づく検索候補を表示できます。たとえば、ユーザーが以前に「puppies」を検索した場合、そのユーザーが同じクエリを入力し始めると、そのクエリが候補として表示されます。図 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 を含めることもできます。これにより、候補テーブルに列がもう 1 つ追加され、各候補で 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>
    

検索可能性の設定の変更

候補プロバイダを使用するようにシステムを設定するには、android:searchSuggestAuthority 属性と android:searchSuggestSelection 属性を検索可能性の設定ファイルの <searchable> 要素に追加する必要があります。次に例を示します。

    <?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 の値には、コンテンツ プロバイダで使用されている権限と完全に一致する、コンテンツ プロバイダの完全修飾名(上の例の AUTHORITY 文字列)を指定する必要があります。

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() メソッドは、1 つ目のパラメータとして検索クエリ文字列を受け取ります。また、候補の 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();
    

この操作は、[検索履歴を消去] メニュー項目、ユーザー設定項目、ボタンのいずれか(デベロッパーが選択)から実行します。また、ユーザーが本当に検索履歴の削除を求めていることを確認するための確認ダイアログを表示する必要があります。