在 Android 搜索对话框或搜索 widget 中,您可以根据近期的搜索查询提供搜索建议。例如,如果用户查询“小狗”,那么当用户再次输入同一查询时,该查询会显示为建议。图 1 显示了包含近期查询建议的搜索对话框示例。
在开始之前,请实现搜索对话框或搜索微件,以便在您的应用中进行基本搜索。如需了解具体方法,请参阅创建搜索界面。
基础知识
近期查询建议是已保存的搜索。当用户选择某条建议时,可搜索 activity 会收到一个 ACTION_SEARCH
intent,其中包含该建议,即您的可搜索 activity 已处理的搜索查询。
要提供近期查询建议,您需要执行以下操作:
- 实现一个可搜索 activity。
- 创建扩展
SearchRecentSuggestionsProvider
的 content provider,并在应用清单中声明它。 - 使用关于提供搜索建议的内容提供程序的信息来修改可搜索配置。
- 每次执行搜索时,都将查询保存到内容提供程序。
就像 Android 系统显示搜索对话框一样,它会在对话框或搜索 widget 下方显示搜索建议。您需要提供系统从中检索建议的来源。
如果系统发现您的 activity 可搜索并提供搜索建议,当用户输入查询时,会发生以下情况:
- 系统获取搜索查询文本(用户开始输入的任何内容),并对包含建议的内容提供程序执行查询。
- content provider 会返回一个
Cursor
,它指向与搜索查询文本匹配的所有建议。 - 系统会显示
Cursor
提供的建议列表。
显示近期查询建议后,可能会发生以下情况:
- 如果用户输入其他键或以任何方式更改查询,系统会重复执行上述步骤并更新建议列表。
- 如果用户执行搜索,系统会忽略建议,并使用常规
ACTION_SEARCH
intent 将搜索传递给可搜索 Activity。 - 如果用户选择一条建议,系统会使用建议的文本作为查询,向您的可搜索 activity 传递
ACTION_SEARCH
intent。
您为 content provider 扩展的 SearchRecentSuggestionsProvider
类会自动执行上述步骤中的工作,因此需要编写的代码很少。
创建 content provider
近期查询建议所需的 content provider 是 SearchRecentSuggestionsProvider
的实现。此类会为您完成所有操作。您只需编写一个类构造函数来执行一行代码。
例如,以下是近期查询建议的 content provider 的完整实现:
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()
的调用会传递搜索授权方的名称和数据库模式。搜索授权方可以是任何唯一字符串,但最佳实践是对 content provider 使用完全限定名称,例如,软件包名称后跟提供程序的类名称。例如 "com.example.MySuggestionProvider"
。
数据库模式必须包含 DATABASE_MODE_QUERIES
,并且可以选择包含 DATABASE_MODE_2LINES
,后者会在建议表格中添加一列,以便您为每个建议提供第二行文本。如果您要在每条建议中提供两行代码,请参阅以下示例:
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
类和可搜索配置中所用的相同授权字符串来声明 content provider。例如:
<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
的值必须是 content provider 的完全限定名称,与 content provider 中使用的授权完全匹配,例如上述示例中的 "com.example.MySuggestionProvider"
。
android:searchSuggestSelection
的值必须是一个前面带有空格的问号:" ?"
。这是 SQLite 选择参数的占位符,会自动替换为用户输入的查询文本。
保存查询
如需填充近期查询的集合,请将可搜索 activity 收到的每个查询添加到 SearchRecentSuggestionsProvider
。为此,请创建一个 SearchRecentSuggestions
实例,并在每次可搜索 Activity 收到查询时调用 saveRecentQuery()
。例如,以下代码段展示了如何在 Activity 的 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
构造函数需要的授权方和数据库模式与 content provider 声明的模式相同。
saveRecentQuery()
方法将搜索查询字符串作为第一个参数,并视需要包含第二个字符串作为建议的第二行或 null。只有在您使用 DATABASE_MODE_2LINES
为搜索建议启用两行模式时,才需要使用第二个参数。如果您启用两行模式,则在系统查找匹配的建议时,查询文本会与第二行进行匹配。
清除建议数据
为了保护用户的隐私,请始终为用户提供清除近期查询建议的方法。如需清除查询历史记录,请调用 clearHistory()
。例如:
Kotlin
SearchRecentSuggestions(this, HelloSuggestionsProvider.AUTHORITY, HelloSuggestionsProvider.MODE) .clearHistory()
Java
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE); suggestions.clearHistory();
通过选择“清除搜索记录”菜单项、偏好设置项或按钮来执行此操作。 提供一个确认对话框,验证用户是否要删除其搜索记录。