创建搜索界面
当您准备好向应用程序添加搜索功能时,Android会帮助您使用显示在活动窗口顶部的搜索对话框或可以在布局中插入的搜索窗口小部件来实现用户界面。搜索对话框和窗口小部件都可以将用户的搜索查询传递给应用程序中的特定活动。这样,用户可以从搜索对话框或小部件可用的任何活动发起搜索,并且系统启动适当的活动以执行搜索并呈现结果。
搜索对话框和小部件可用的其他功能包括:
- 声音搜索
- 根据最近的查询搜索建议
- 搜索与您的申请数据中的实际结果相匹配的建议
本指南介绍如何使用搜索对话框或搜索小部件设置应用程序,以提供由Android系统协助提供搜索查询的搜索界面。
基础
在开始之前,您应该决定是使用搜索对话框还是搜索小部件来实现搜索界面。两者都提供相同的搜索功能,但方式略有不同:
- 搜索对话框是由Android系统控制的UI组件。当用户激活时,搜索对话框将显示在活动的顶部,如图1所示。
Android系统控制搜索对话框中的所有事件。当用户提交查询时,系统会将查询传递给您指定用于处理搜索的活动。该对话框还可以在用户键入时提供搜索建议。 - 搜索小部件是SearchView的一个实例,您可以将其放置在布局中的任何位置。默认情况下,搜索窗口小部件的行为类似于标准的EditText窗口小部件,但不执行任何操作,但您可以对其进行配置,以便Android系统处理所有输入事件,向相应活动提供查询,并提供搜索建议(就像搜索一样)对话)。
注意:如果需要,您可以使用各种回调方法和侦听器自行处理搜索窗口小部件中的所有用户输入。但是,本文档重点介绍如何将搜索小部件与系统集成以实现辅助搜索。如果您想自己处理所有用户输入,请阅读SearchView及其嵌套接口的参考文档。
当用户从搜索对话框或搜索小部件执行搜索时,系统会创建一个Intent并将用户查询存储在其中。然后,系统启动您声明要处理搜索的活动(“可搜索活动”)并将其传递给意图。要设置此类辅助搜索的应用程序,您需要以下内容:
- 可搜索的配置
一个XML文件,用于配置搜索对话框或窗口小部件的某些设置。它包括搜索框的语音搜索,搜索建议和提示文本等功能的设置。 - 可搜索的活动
接收搜索查询,搜索数据并显示搜索结果的活动。 - 或者,一个SearchView小部件
使用搜索小部件,您可以将搜索框放在活动的任何位置。您应该通常在应用栏中将SearchView用作操作视图,而不是将其放在活动布局中。
本文档的其余部分将向您展示如何使用搜索对话框或搜索小部件创建可搜索的配置,可搜索的活动以及实现搜索界面。
创建可搜索的配置
您需要的第一件事是称为可搜索配置的XML文件。它配置搜索对话框或窗口小部件的某些UI方面,并定义诸如建议和语音搜索等功能的行为。此文件传统上命名为searchable.xml,必须保存在res / xml / project目录中。
注意:系统使用此文件来实例化SearchableInfo对象,但您无法在运行时自己创建此对象 - 您必须在XML中声明可搜索的配置。
可搜索的配置文件必须包含<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" >
</searchable>
android:label属性是唯一必需的属性。它指向一个字符串资源,它应该是应用程序名称。在为快速搜索框启用搜索建议之前,用户实际上看不到此标签。此时,此标签在系统设置的可搜索项目列表中可见。
虽然不是必需的,但我们建议您始终包含android:hint属性,该属性在用户输入查询之前在搜索框中提供提示字符串。提示非常重要,因为它为用户提供了搜索内容的重要线索。
提示:为了与其他Android应用程序保持一致,您应该将android:hint的字符串格式化为“Search <content-or-product>”。例如,“搜索歌曲和艺术家”或“搜索YouTube”。
<searchable>元素接受其他几个属性。但是,在添加搜索建议和语音搜索等功能之前,您不需要大多数属性。有关可搜索配置文件的详细信息,请参阅“可搜索配置”参考文档。
创建可搜索的活动
可搜索的活动是应用程序中的活动,它根据查询字符串执行搜索并显示搜索结果。
当用户在搜索对话框或窗口小部件中执行搜索时,系统会启动您的可搜索活动,并使用ACTION_SEARCH操作在Intent中提供搜索查询。您的可搜索活动从intent的QUERY extra中检索查询,然后搜索您的数据并显示结果。
由于您可以在应用程序中的任何其他活动中包含搜索对话框或窗口小部件,因此系统必须知道哪些活动是您的可搜索活动,因此它可以正确地提供搜索查询。因此,您必须首先在Android清单文件中声明您的可搜索活动。
声明可搜索的活动
如果您还没有,请创建一个将执行搜索并显示结果的活动。您不需要实现搜索功能 - 只需创建一个可以在清单中声明的活动。在清单的<activity>元素内:
1.在<intent-filter>元素中声明活动以接受ACTION_SEARCH目的。
2.在<meta-data>元素中指定要使用的可搜索配置。
例如:
<application ... >
<activity android:name=".SearchableActivity" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
...
</application>
<meta-data>元素必须包含值为“android.app.searchable”的android:name属性和包含对可搜索配置文件的引用的android:resource属性(在此示例中,它指的是res / xml / searchable.xml文件)。
执行搜索
在清单中声明可搜索的活动后,在可搜索的活动中执行搜索涉及三个步骤:
1.Receiving the query
2.Searching your data
3.Presenting the results
传统上,您的搜索结果应该以ListView的形式呈现,因此您可能希望您的可搜索活动扩展ListActivity。它包含一个带有单个ListView的默认布局,并提供了一些使用ListView的便捷方法。
接收查询
当用户从搜索对话框或窗口小部件执行搜索时,系统会启动您的可搜索活动并向其发送ACTION_SEARCH目的。此意图在QUERY字符串extra中包含搜索查询。您必须在活动开始时检查此意图并提取字符串。例如,以下是您可搜索活动开始时如何获取搜索查询:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
// Get the intent, verify the action and get the query
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
}
QUERY字符串始终包含在ACTION_SEARCH目标中。在此示例中,检索查询并将其传递到本地doMySearch()方法,在该方法中完成实际的搜索操作。
搜索您的数据
存储和搜索数据的过程对您的应用程序而言是独一无二的。您可以通过多种方式存储和搜索数据,但本指南未向您展示如何存储数据并进行搜索。根据您的需求和数据格式,您应该仔细考虑存储和搜索数据。但是,以下是您可以应用的一些提示:
- 如果您的数据存储在设备上的SQLite数据库中,则执行全文搜索(使用FTS3而不是LIKE查询)可以跨文本数据提供更强大的搜索,并且可以显着更快地生成结果。有关FTS3和SQLiteDatabase类的信息,请参阅sqlite.org以获取有关Android上SQLite的信息。另请参阅Searchable Dictionary示例应用程序,以查看使用FTS3执行搜索的完整SQLite实现。
- 如果您的数据是在线存储的,那么用户的数据连接可能会阻止感知的搜索性能。在搜索返回之前,您可能希望显示旋转的进度轮。有关如何显示进度轮的信息,请参阅android.net以获取网络API的参考和创建进度对话框。
无论您的数据位于何处以及如何搜索,我们都建议您使用适配器将搜索结果返回到可搜索的活动。这样,您就可以轻松地在ListView中显示所有搜索结果。如果您的数据来自SQLite数据库查询,则可以使用CursorAdapter将结果应用于ListView。如果您的数据采用其他类型的格式,则可以创建BaseAdapter的扩展。
关于适配器
适配器将一组数据中的每个项绑定到一个View对象。将适配器应用于ListView时,每个数据作为单独的视图插入到列表中。适配器只是一个接口,因此需要诸如CursorAdapter(用于绑定来自Cursor的数据)的实现。如果现有实现都不适用于您的数据,那么您可以从BaseAdapter实现自己的实现。安装API Level 4的SDK Samples包以查看Searchable Dictionary的原始版本,该版本创建一个自定义适配器以从文件中读取数据。
展示结果
如上所述,搜索结果的推荐UI是ListView,因此您可能希望可搜索的活动扩展ListActivity。然后,您可以调用setListAdapter(),向其传递绑定到您的数据的适配器。这会将所有搜索结果注入活动ListView。
有关在列表中显示结果的更多帮助,请参阅ListActivity文档。
另请参阅Searchable Dictionary示例,以获得如何搜索SQLite数据库并使用适配器在ListView中提供结果的完整演示。
使用“搜索”对话框
搜索对话框在屏幕顶部提供了一个浮动搜索框,左侧是应用程序图标。搜索对话框可以在用户键入时提供搜索建议,并且当用户执行搜索时,系统将搜索查询发送到执行搜索的可搜索活动。但是,如果您正在为运行Android 3.0的设备开发应用程序,则应考虑使用搜索窗口小部件(请参阅使用“搜索窗口小部件”部分)。
默认情况下,搜索对话框始终处于隐藏状态,直到用户激活它。您的应用程序可以通过调用onSearchRequested()来激活搜索对话框。但是,在为活动启用搜索对话框之前,此方法不起作用。
要启用搜索对话框,您必须向系统指明哪些可搜索活动应从搜索对话框接收搜索查询,以便执行搜索。例如,在上一节“创建可搜索活动”中,创建了一个名为SearchableActivity的可搜索活动。如果您想要一个名为OtherActivity的单独活动来显示搜索对话框并将搜索提供给SearchableActivity,则必须在清单中声明SearchableActivity是可用于OtherActivity中搜索对话框的可搜索活动。
要为活动的搜索对话框声明可搜索活动,请在相应活动的<activity>元素内添加<meta-data>元素。 <meta-data>元素必须包含指定可搜索活动的类名的android:value属性和值为“android.app.default_searchable”的android:name属性。
例如,下面是可搜索活动SearchableActivity和另一个活动OtherActivity的声明,它使用SearchableActivity执行从搜索对话框执行的搜索:
<application ... >
<!-- this is the searchable activity; it performs searches -->
<activity android:name=".SearchableActivity" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
<!-- this activity enables the search dialog to initiate searches
in the SearchableActivity -->
<activity android:name=".OtherActivity" ... >
<!-- enable the search dialog to send searches to SearchableActivity -->
<meta-data android:name="android.app.default_searchable"
android:value=".SearchableActivity" />
</activity>
...
</application>
由于OtherActivity现在包含一个<meta-data>元素来声明要用于搜索的可搜索活动,因此该活动已启用搜索对话框。当用户处于此活动时,onSearchRequested()方法将激活搜索对话框。当用户执行搜索时,系统启动SearchableActivity并向其传递ACTION_SEARCH意图。
注意:默认情况下,可搜索活动本身提供搜索对话框,因此您无需将此声明添加到SearchableActivity。
如果希望应用程序中的每个活动都提供搜索对话框,请将上面的<meta-data>元素作为<application>元素的子元素插入,而不是每个<activity>。这样,每个活动都会继承该值,提供搜索对话框,并将搜索提供给相同的可搜索活动。 (如果您有多个可搜索的活动,则可以通过在各个活动中放置不同的<meta-data>声明来覆盖默认的可搜索活动。)
现在,您的活动已启用搜索对话框,您的应用程序已准备好执行搜索。
调用搜索对话框
虽然某些设备提供专用的搜索按钮,但按钮的行为可能因设备而异,许多设备根本不提供“搜索”按钮。因此,在使用搜索对话框时,您必须在UI中提供一个搜索按钮,通过调用onSearchRequested()来激活搜索对话框。
例如,您应在选项菜单或UI布局中添加一个调用onSearchRequested()的搜索按钮。为了与Android系统和其他应用程序保持一致,您应该使用操作栏图标包中提供的Android搜索图标标记您的按钮。
注意:如果您的应用使用了应用栏,则不应将搜索对话框用于搜索界面。而是将搜索小部件用作应用栏中的可折叠视图。
您还可以启用“类型到搜索”功能,当用户开始在键盘上键入时,该功能会激活搜索对话框 - 键击将插入到搜索对话框中。您可以在活动的onCreate()方法中调用setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL),在活动中启用类型到搜索。
搜索对话框对您的活动生命周期的影响
搜索对话框是一个浮动在屏幕顶部的对话框。它不会导致活动堆栈发生任何变化,因此当出现搜索对话框时,不会调用任何生命周期方法(例如onPause())。您的活动只会丢失输入焦点,因为输入焦点会显示在搜索对话框中。
如果要在激活搜索对话框时收到通知,请覆盖onSearchRequested()方法。当系统调用此方法时,表示您的活动已将输入焦点丢失到搜索对话框,因此您可以执行适合该事件的任何工作(例如暂停游戏)。除非您传递搜索上下文数据(如下所述),否则您应该通过调用超类实现来结束该方法。例如:
@Override
public boolean onSearchRequested() {
pauseSomeStuff();
return super.onSearchRequested();
}
如果用户通过按“返回”按钮取消搜索,则搜索对话框将关闭,活动将重新获得输入焦点。您可以注册以在使用setOnDismissListener()和/或setOnCancelListener()关闭搜索对话框时收到通知。您应该只需要注册OnDismissListener,因为每次搜索对话框关闭时都会调用它。 OnCancelListener仅适用于用户显式退出搜索对话框的事件,因此在执行搜索时不会调用它(在这种情况下,搜索对话框自然会消失)。
如果当前活动不是可搜索的活动,则一旦用户执行搜索(当前活动接收onPause()等,则触发正常活动生命周期事件,如活动文档中所述)。但是,如果当前活动是可搜索的活动,则会发生以下两种情况之一:
a.默认情况下,可搜索活动通过调用onCreate()接收ACTION_SEARCH意图,并将活动的新实例带到活动堆栈的顶部。现在,活动堆栈中存在两个可搜索活动的实例(因此,按“返回”按钮将返回到可搜索活动的上一个实例,而不是退出可搜索活动)。
b.如果将android:launchMode设置为“singleTop”,则可搜索活动通过调用onNewIntent(Intent)接收ACTION_SEARCH意图,并在此处传递新的ACTION_SEARCH意图。例如,以下是您可以处理这种情况的方法,其中可搜索活动的启动模式为“singleTop”:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
handleIntent(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
}
与“执行搜索”一节中的示例代码相比,处理搜索意图的所有代码现在都在handleIntent()方法中,因此onCreate()和onNewIntent()都可以执行它。
当系统调用onNewIntent(Intent)时,活动尚未重新启动,因此getIntent()方法返回与onCreate()一起接收的相同意图。这就是你应该在onNewIntent(Intent)中调用setIntent(Intent)的原因(以便在将来调用getIntent()时更新活动保存的意图)。
使用“singleTop”启动模式的第二种情况通常是理想的,因为一旦搜索完成,用户将执行额外的搜索,如果您的应用程序创建可搜索活动的多个实例,那么这是一种糟糕的体验。因此,我们建议您在应用程序清单中将可搜索活动设置为“singleTop”启动模式。例如:
<activity android:name=".SearchableActivity"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
传递搜索上下文数据
在某些情况下,对于每次搜索,您都可以对可搜索活动内的搜索查询进行必要的优化。但是,如果要根据用户执行搜索的活动优化搜索条件,则可以在系统发送到可搜索活动的意图中提供其他数据。您可以传递APP_DATA包中的附加数据,该包含在ACTION_SEARCH目的中。
要将此类数据传递给可搜索的活动,请覆盖用户可以执行搜索的活动的onSearchRequested()方法,使用其他数据创建Bundle,并调用startSearch()以激活搜索对话框。例如:
@Override
public boolean onSearchRequested() {
Bundle appData = new Bundle();
appData.putBoolean(SearchableActivity.JARGON, true);
startSearch(null, false, appData, false);
return true;
}
返回“true”表示您已成功处理此回调事件并调用startSearch()以激活搜索对话框。用户提交查询后,会将其与您添加的数据一起发送到您的可搜索活动。您可以从APP_DATA Bundle中提取额外数据以优化搜索。例如:
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
boolean jargon = appData.getBoolean(SearchableActivity.JARGON);
}
注意:切勿从onSearchRequested()回调方法外部调用startSearch()方法。要激活活动中的搜索对话框,请始终调用onSearchRequested()。否则,不会调用onSearchRequested(),并且会错过自定义(例如上例中添加的appData)。
使用搜索小组件
SearchView小部件在Android 3.0及更高版本中可用。如果您正在开发Android 3.0应用程序并决定使用搜索小部件,我们建议您将搜索小部件作为操作视图插入应用栏,而不是使用搜索对话框(而不是放置搜索小部件)在你的活动布局中)。例如,图2显示了应用栏中的搜索小部件。
搜索小部件提供与搜索对话框相同的功能。它在用户执行搜索时启动适当的活动,并且可以提供搜索建议并执行语音搜索。如果您不能将搜索小部件放在操作栏中,则可以将搜索小部件放在活动布局中的某个位置。
注意:当您将搜索窗口小部件用作操作视图时,对于搜索窗口小部件不适合操作栏的情况,您仍可能需要支持使用搜索对话框。请参阅以下有关使用窗口小部件和对话框的部分。
配置搜索小部件
在您创建了可搜索的配置和可搜索的活动之后,如上所述,您需要为每个SearchView启用辅助搜索。您可以通过调用setSearchableInfo()并向其传递代表您的可搜索配置的SearchableInfo对象来完成此操作。
您可以通过在SearchManager上调用getSearchableInfo()来获取对SearchableInfo的引用。
例如,如果您在应用栏中使用SearchView作为操作视图,则应在onCreateOptionsMenu()回调期间启用该窗口小部件:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the options menu from XML
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService()(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
// Assumes current activity is the searchable activity
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
return true;
}
这就是你所需要的一切。现在已配置搜索窗口小部件,系统将为您的可搜索活动提供搜索查询。您还可以为搜索小部件启用搜索建议。
注意:如果您想自己处理所有用户输入,可以使用一些回调方法和事件侦听器。有关更多信息,请参阅SearchView的参考文档及其相应事件侦听器的嵌套接口。
有关操作栏中操作视图的更多信息,请参阅操作视图和操作提供程序。
其他搜索小部件功能
SearchView小部件允许您可能需要的一些其他功能:
提交按钮
默认情况下,没有提交搜索查询的按钮,因此用户必须按键盘上的“返回”键才能启动搜索。您可以通过调用setSubmitButtonEnabled(true)添加“提交”按钮。
搜索建议的查询细化
当您启用搜索建议时,通常希望用户只需选择一个建议,但他们可能还希望优化建议的搜索查询。您可以通过调用setQueryRefinementEnabled(true)在每个建议旁添加一个按钮,该建议在搜索框中插入建议以供用户进行优化。
能够切换搜索框可见性
默认情况下,搜索小部件是“图标化”,意味着它仅由搜索图标(放大镜)表示,并在用户触摸时展开以显示搜索框。如上所示,您可以通过调用setIconifiedByDefault(false)默认显示搜索框。您还可以通过调用setIconified()来切换搜索小部件外观。
SearchView类中还有其他几个API,允许您自定义搜索小部件。但是,大多数只在您自己处理所有用户输入时使用,而不是使用Android系统提供搜索查询和显示搜索建议。
同时使用小部件和对话框
如果您将操作栏中的搜索小部件作为操作视图插入,并启用它以显示在操作栏中“如果有空间”(通过设置android:showAsAction =“ifRoom”),那么有可能搜索窗口小部件不会显示为操作视图,但菜单项将显示在溢出菜单中。例如,当您的应用程序在较小的屏幕上运行时,操作栏中可能没有足够的空间来显示搜索小部件以及其他操作项或导航元素,因此菜单项将显示在溢出菜单中。当放置在溢出菜单中时,该项目就像普通菜单项一样工作,并且不显示操作视图(搜索小部件)。
要处理这种情况,当用户从溢出菜单中选择搜索对话框时,您附加搜索窗口小部件的菜单项应激活搜索对话框。为了实现这一点,您必须实现onOptionsItemSelected()来处理“搜索”菜单项并通过调用onSearchRequested()打开搜索对话框。
有关操作栏中的项目如何工作以及如何处理此情况的详细信息,请参阅操作栏开发人员指南。
另请参阅Searchable Dictionary以获取使用对话框和窗口小部件的示例实现。
添加语音搜索
您可以通过将android:voiceSearchMode属性添加到可搜索的配置中,将语音搜索功能添加到搜索对话框或小部件中。这会添加一个语音搜索按钮,用于启动语音提示。当用户完成发言后,转录的搜索查询将发送到您的可搜索活动。
例如:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" >
</searchable>
值showVoiceSearchButton是启用语音搜索所必需的,而第二个值launchRecognizer指定语音搜索按钮应启动识别器,该识别器将转录的文本返回到可搜索的活动。
您可以提供其他属性来指定语音搜索行为,例如预期的语言和要返回的最大结果数。有关可用属性的更多信息,请参见“可搜索的配置”参考。
注意:请仔细考虑语音搜索是否适合您的应用程序。使用语音搜索按钮执行的所有搜索都会立即发送到您的可搜索活动,而用户无需查看转录的查询。充分测试语音识别并确保它了解用户可能在您的应用程序中提交的查询类型。
添加搜索建议
在Android系统的帮助下,搜索对话框和搜索小部件都可以在用户输入时提供搜索建议。系统管理建议列表并在用户选择建议时处理事件。
您可以提供两种搜索建议:
最近的查询搜索建议
这些建议只是用户以前在您的应用程序中用作搜索查询的单词。
请参阅添加最近查询建议。
自定义搜索建议
这些是您从自己的数据源提供的搜索建议,以帮助用户立即选择正在搜索的正确拼写或项目。图3显示了字典应用程序的自定义建议示例 - 用户可以选择建议立即转到定义。
请参阅添加自定义建议