当用户使用Search Dialog或Search Widget输入搜索查询时,在界面上会提供搜索建议,用户可以选择可能的查询,使得搜索变得更简单。可以通过以下步骤实现这一点:
1.系统把查询文本传给已定义的内容提供者,该内容提供者包含搜索建议。
2.内容提供者返回一个游标,它基于查询指向所有建议的列表。
3.系统显示该建议。
如果用户选择其中一条建议,会向可搜索的活动发送intent,包含定制的操作和数据。
该API提供一种简单的方式可以基于搜索历史(最近的查询记录)显示建议,并且提供创建定制(由应用逻辑生成)建议的途径。
最近的查询建议
SearchRecentSuggestionsProvider类为了搜索建议保存历史搜索的提供者的基础类,它涵盖返回相应结果的绝大部分的必要逻辑。通过这种方式,可以减少实现搜索历史建议系统所需的代码量和配置。
要实现搜索提供建议的功能,首先创建一个类,继承SearchRecentSuggestionsProvider类,并调用setupSuggestions方法定义权限(authority)和模式。
package com.oreilly.demo.android.pa.searchdemo;import android.content.SearchRecentSuggestionsProvider;public class CustomSearchSuggestionProvider extends SearchRecentSuggestionsProvider { public final static String AUTHORITY = /"com.oreilly.demo.android.pa.searchdemo.CustomSearchSuggestionProvider/"; public final static int MODE = DATABASE_MODE_QUERIES; public CustomSearchSuggestionProvider { super; setupSuggestions(AUTHORITY, MODE); }}
构建了提供者后,必须在manifest文件中声明它。这里,关键是引用同样的authority字符串,该字符串是在定制的SearchRecentSuggestionsProvider中定义的。
<application> ... <provider android:name=/".searchdemo.CustomSearchSuggestionProvider/" android:authorities= /"com.oreilly.demo.android.pa.searchdemo.CustomSearchSuggestionProvider/" /> ...</application>
该权限还必须在可搜索的XML配置文件中作为android:searchSuggestAuthority属性的引用。此外,还需要定义android:searchSuggestSelection,其值为“?”(注意前面有个空格),把查询作为SQLite选择参数传给查询。
<?xml version=/"1.0/" encoding=/"utf-8/"?><searchable xmlns:android=/"http://schemas.android.com/apk/res/android/" android:label=/"@string/app_name/" android:hint=/"@string/search_hint/" android:voiceSearchMode=/"showVoiceSearchButton|launchRecognizer/" android:searchSuggestAuthority= /"com.oreilly.demo.android.pa.searchdemo.CustomSearchSuggestionProvider/" android:searchSuggestSelection=/" ?/" ></searchable>
最后,声明了SearchRecentSuggestionsProvider类并设置其配置后,查询需要添加到搜索历史中。这是通过调用SearchRecentSuggestions的saveRecentQuery方法并把查询传给它来实现的。
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, CustomSearchSuggestionProvider.AUTHORITY, CustomSearchSuggestionProvider.MODE);suggestions.saveRecentQuery(query, null); // save querysuggestions.clearHistory; // clear history
定制查询建议
要创建由某些应用逻辑提供的定制查询建议,需要考虑的主要点在于接收查询并返回游标Cursor的内容提供者。该Cursor引用系统要显示给用户的建议数据的行号。在特定情况下,系统期望数据包含一些特定的列,如表14-1所示。有些列是必须的,其余则是可选的。
表14-1:定制查询建议的Cursor数据
表14-1:定制查询建议的Cursor数据(续)
表14-1:定制查询建议的Cursor数据(续)
值得注意的是,如果搜索建议不是保存成表格形式(如SQLite表),可以很容易遵循系统需要的字段,应该创建包含需要字段的MatrixCursor,使用addRow(Object)方法添加数据。
不管Cursor规范如何,内容提供者的query方法必须返回之前定义的Cursor类。query方法定义如下:
public Cursor query(Uri uri, String projection, String selection, String selectionArgs, String sortOrder)
它从系统中接收以下参数:
uri
参照以下定义。
projection
该参数值总是空。
selection
搜索配置项android:searchSuggestSelection的值。
selectionArgs
如果在可搜索配置中声明了android:searchSuggestSelection属性,该参数包含搜索查询作为数组的唯一元素,否则为空。它是用户搜索的基础项。
sortOrder
该参数值总是空。
uri格式如下:
content://your.authority/optional.suggest.path/some_uri_path_that_you_definned/query
your.authority是之前在可搜索配置XML文件中定义的android.searchSuggestAuthority属性。optional.suggest.path是在可搜索配置XML文件中定义的可选的android:searchSuggestPath属性。对于同一个内容提供者,如果有多个可搜索的活动,它确保可以从多个活动中区分出查询的潜在源文件。其中,some_uri_path_that_you_defined是定义的常量字符串,query是传递给用户的真正查询字符串。该查询字符串可能是URI编码,因而需要解码。
以下是query方法示例。
还需要在manifest文件中指定内容提供者。
<application> ... <provider android:name=/".searchdemo.SearchDBProvider/" android:authorities= /"com.oreilly.demo.android.pa.searchdemo.SearchDBProvider/" /> ...</application>
然后配置可搜索配置项,至少把android:searchSuggestAuthority项设置成之前定义的权限字符串。
<?xml version=/"1.0/" encoding=/"utf-8/"?><searchable xmlns:android=/"http://schemas.android.com/apk/res/android/" android:label=/"@string/app_name/" android:searchSuggestAuthority= /"com.oreilly.demo.android.pa.searchdemo.SearchDBProvider/" ></searchable>
其他方面如定制的intent可以通过android:searchSuggestIntentAction,在可搜索配置中指定。通过定制的intent,可搜索的活动可以区分常见的搜索查询(通过android.Intent.action.SEARCH预设置)和建议的搜索查询。以下例子使用android.Intent.action.VIEW实现定制intent。
<?xml version=/"1.0/" encoding=/"utf-8/"?> <searchable xmlns:android= /"http://schemas.android.com/apk/res/android/" android:label=/"@string/app_name/" android:searchSuggestAuthority= /"com.oreilly.demo.android.pa.searchdemo.SearchDBProvider/" android:searchSuggestIntentAction=/"android.Intent.action.VIEW/" ></searchable>
在这个例子中,可搜索的activity需要处理Intent.ACTION_VIEW以及Intent.ACTION_SEARCH。
Intent intent = getIntent;if (Intent.ACTION_SEARCH.equals(intent.getAction)) { String query = intent.getStringExtra(SearchManager.QUERY).toLowerCase; search(query); // go do the search against the searchlogic} else if (Intent.ACTION_VIEW.equals(intent.getAction)) { Uri data = intent.getData; loadData(data); // do something with this data}
最后,如果希望在快速搜索框中显示搜索建议,可搜索的配置应该把android:includeInGlobalSearch中设置成true。系统会自动快速显示用户从快速搜索框中选中的搜索建议。系统已经从内容提供者缓存了这些搜索建议,因此可以快速访问它们。一旦快速搜索框可以使用应用的搜索建议,对于特定查询,应用的排名决定了这些搜索建议如何展现给用户。它可能取决于其他应用包含该查询结果,以及用户选中哪些查询结果。对于特定查询,你的建议如何排序甚至是否显示都是不确定的。一般而言,提供高质量的查询结果会提升你的应用建议在显著位置展示的可能性,而提供低质量的查询建议的应用往往排名更靠后甚至不会显示。