创建搜索界面

当您准备好为应用添加搜索功能时,Android 可以帮助您 通过顶部显示的搜索对话框实现界面 或您可以插入布局中的搜索微件。 搜索对话框和搜索微件均可将用户的搜索查询传递给 应用内的特定活动这样,用户就可以从任意区域发起搜索 activity,其中搜索对话框或 widget 可用,并且系统启动 执行搜索和显示结果所需的相应 activity。

搜索对话框和搜索微件提供的其他功能包括:

  • 语音搜索
  • 基于近期查询的搜索建议
  • 与应用数据中的实际结果相符的搜索建议

本文档介绍了如何设置您的应用以提供搜索界面 在 Android 系统的帮助下投放搜索查询 搜索对话框或搜索微件。

相关资源:

基础知识

在开始之前,请确定您是否要实现搜索界面 搜索微件。它们提供的搜索相同 只不过在方式上稍有不同

  • 搜索对话框是一个界面组件,由 Android 系统。用户激活搜索对话框后,搜索对话框的 activity 的顶部。

    Android 系统控制搜索对话框中的所有事件。当 当用户提交查询时,系统会将该查询传递给 来处理搜索。该对话框还可提供 在用户输入内容时提供建议。

  • 搜索微件SearchView 放置在布局中的任意位置。默认情况下,搜索微件的行为类似于 标准 EditText 并且不执行任何操作,但您可以对其进行配置 系统处理所有输入事件,将查询传送到相应的 以及提供搜索建议 对话框。
。 <ph type="x-smartling-placeholder">

当用户从搜索对话框或搜索微件中执行搜索时, 系统会创建一个 Intent和 其中存储了用户查询然后,系统会启动 声明用于处理搜索(即“可搜索 activity”),并提供 intent。要设置您的应用以使用此类辅助搜索,您需要 以下:

  • 搜索配置
    此 XML 文件用于为搜索对话框或搜索微件配置某些设置。 其中包括语音搜索、搜索建议 和提示文字。
  • 可搜索的 activity
    Activity 接收搜索查询、搜索您的数据并显示搜索 结果。
  • 搜索界面,由以下任一项提供:
    • 搜索对话框
      默认情况下,搜索对话框处于隐藏状态。它会显示在 当你通话时屏幕 onSearchRequested() 当用户点按您的搜索按钮时触发。
    • SearchView 微件
      通过使用搜索微件,您可以将搜索框放在 包括应用栏中的操作视图。

本文档的其余部分介绍了如何创建搜索配置 以及如何使用 搜索对话框或搜索微件。

创建可搜索配置

首先,您需要一个称为 搜索配置。 它用于配置搜索对话框或搜索微件的某些界面方面,并定义如何 以及语音搜索等功能的行为。此文件一直是 名为 searchable.xml,必须保存在 res/xml/ 项目目录中。

<ph type="x-smartling-placeholder">

搜索配置文件必须包含 <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 属性,用于在搜索内容中提供提示字符串 复选框。提示很重要 可为用户提供有关搜索内容的重要线索。

<ph type="x-smartling-placeholder">

<searchable> 元素接受其他几个属性。 不过,在添加诸如 搜索建议语音搜索。如需详细了解 请参阅 搜索配置 参考文档。

创建可搜索 activity

可搜索 activity 是指应用中执行搜索操作的 Activity, 基于查询字符串进行搜索,并显示搜索结果。

当用户在搜索对话框或搜索微件中执行搜索时,系统会 启动可搜索 activity 并以 Intent 替换为 ACTION_SEARCH 操作。可搜索 Activity 会从 intent 的 QUERY extra,然后搜索您的数据并显示结果。

因为您可以将搜索对话框或搜索微件包含在 您的应用,系统必须知道哪个 activity 是您的可搜索 activity, 确保它可以正确提供搜索查询。因此,首先声明可供搜索的 Android 清单文件中的 activity。

声明可搜索 activity

如果您还没有 Activity,请创建一个执行 搜索和显示结果。您无需实施搜索 只需创建一个可在 清单。在清单的 <activity> 元素,请执行以下操作:

  1. ACTION_SEARCH <intent-filter> 元素。
  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:name 属性,值为 "android.app.searchable"android:resource 属性与可搜索配置文件的引用。在 它引用了 res/xml/searchable.xml 文件。

<ph type="x-smartling-placeholder">

执行搜索

在清单中声明可搜索 Activity 后,请按照下面的 在可搜索 Activity 中执行搜索的步骤:

  1. 接收查询
  2. 搜索您的数据
  3. 呈现结果

接收查询

当用户从搜索对话框或搜索微件中执行搜索时,系统会 启动您的可搜索 activity 并向其发送 ACTION_SEARCH intent。此 intent 在 QUERY 字符串中携带搜索查询 extra。在 activity 启动时检查此 intent 并提取字符串。 例如,下面介绍了如何在 活动开始:

Kotlin

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

    // Verify the action and get the query.
    if (Intent.ACTION_SEARCH == intent.action) {
        intent.getStringExtra(SearchManager.QUERY)?.also { query ->
            doMySearch(query)
        }
    }
}

Java

@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 intent。在前面的示例中,查询为 并将其传递给本地 doMySearch() 方法,其中 实际搜索操作完成时的情况。

搜索您的数据

存储和搜索数据的过程对于您的应用来说是唯一的。您可以 可通过多种方式存储和搜索数据,本文档并未介绍具体方法。 考虑如何根据您的需求和数据存储和搜索数据 格式。以下是您或许可以采用的提示:

  • 如果您的数据存储在设备上的 SQLite 数据库中,请执行 全文搜索 - 使用 FTS3,而不是 LIKE 可以在文本数据中进行更强大的搜索,并 以大幅加快结果的生成速度。请参阅 sqlite.org,用于 FTS3 和 SQLiteDatabase 类以了解有关 Android 上的 SQLite 的信息。
  • 如果您的数据是在线存储的,那么用户感知到的搜索效果 被用户的数据连接所禁止。您可能希望 进度指示器。请参阅 android.net 提供了网络 API 的参考信息 ProgressBar 了解有关如何显示进度指示器的信息。
。 <ph type="x-smartling-placeholder">

呈现结果

无论您的数据位于何处以及如何搜索,我们都建议您 您可以使用 Adapter。这个 你可以在一个网页上显示所有搜索结果 RecyclerView。 如果您的数据来自 SQLite 数据库查询,则可以将结果应用于 RecyclerView(使用 CursorAdapter。 如果您的数据采用其他格式,您可以创建 BaseAdapter

Adapter 将一组数据中的每一项绑定到 View 对象。时间 Adapter 会应用于 RecyclerView,每个部分 数据会作为单独的视图插入列表中。“Adapter”现为 一个接口,因此诸如此类的实现 CursorAdapter - 用于绑定 Cursor - 是 所需的资源。如果现有的实现方案都不适合您的数据,您可以 从 BaseAdapter 中实现您自己的自定义。

使用搜索对话框

搜索对话框在屏幕顶部提供了一个浮动搜索框, 应用图标位于屏幕左侧搜索对话框可以提供搜索建议 。当用户执行搜索时,系统会将搜索 传递给执行搜索的可搜索 Activity。

默认情况下,搜索对话框始终处于隐藏状态,直到用户将其激活。 您的应用可以通过调用 onSearchRequested()。不过,只有在您完成上述操作后, 为 activity 启用搜索对话框。

要使搜索对话框能够执行搜索,请向系统指示 可搜索 Activity 必须从搜索对话框接收搜索查询。对于 请参阅上一部分中的示例, 创建一个可搜索的 activity, 已创建名为“SearchableActivity”的 activity。如果您想 一个单独的 activity(例如名为 OtherActivity 的 activity),用于显示 搜索对话框,并将搜索传送到 SearchableActivity,声明 在清单中指示 SearchableActivity 是可搜索 activity 供 OtherActivity 中的搜索对话框使用。

要为 Activity 的搜索对话框声明可搜索 Activity,请将 <meta-data> 元素(位于相应 activity 的 <activity> 元素。<meta-data> 元素必须包含 android:value 属性,用于指定 可搜索 activity 的类名称和 android:name 属性 值为 "android.app.default_searchable"

例如,下面是一个可搜索 Activity 的声明, SearchableActivity 和另一个 activity, 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> 元素,用于声明要将哪个可搜索 activity 用于搜索,则此 activity 会启用搜索对话框。尽管用户 在此 activity 中,onSearchRequested() 方法会激活 搜索对话框。当用户执行搜索时,系统会启动 SearchableActivity,并提供ACTION_SEARCH intent。

<ph type="x-smartling-placeholder">

如果您希望应用中的每个 activity 都提供搜索对话框,请插入 前面的 <meta-data> 元素作为 <application> 元素,而不是每个 <activity>。这样,每项活动 继承该值,提供搜索对话框,并将搜索传递给 相同的可搜索活动。如果您有多个可搜索的 activity,可以 替换默认的可搜索 activity,方法是将另一个 <meta-data> 声明。

现在为您的 activity 启用搜索对话框后,您的应用就可以 执行搜索。

调用搜索对话框

虽然某些设备提供了专用的搜索按钮, 按钮可能因设备而异,而且许多设备不提供搜索功能 按钮。因此,在使用搜索对话框时,您必须提供一个搜索按钮 在界面中通过调用以下函数激活搜索对话框: onSearchRequested()

例如,在 选项菜单或界面布局 调用 onSearchRequested()

<ph type="x-smartling-placeholder">

您还可以启用“输入搜索内容”该功能可启用 搜索对话框。按键为 插入搜索对话框。您可以在 activity 中启用“输入字词进行搜索”功能 通过调用 setDefaultKeyMode - 或 DEFAULT_KEYS_SEARCH_LOCAL:期间 您的活动记录 onCreate() 方法。

搜索对话框对 Activity 生命周期的影响

搜索对话框是 浮动的 Dialog 。它不会导致 activity 堆栈发生任何变化 没有生命周期方法,例如 onPause() - 是 调用。您的 activity 会失去输入焦点,因为将输入焦点提供给 搜索对话框。

如果您希望在激活搜索对话框时收到通知,请替换 onSearchRequested() 方法结合使用。当系统调用此方法时, 表示您的 activity 失去了搜索对话框的输入焦点,因此 您可以执行任何适合该事件的操作,例如暂停游戏。除非 您将传递搜索上下文 (本文档的另一部分对此进行了讨论),使 方法是:

Kotlin

override fun onSearchRequested(): Boolean {
    pauseSomeStuff()
    return super.onSearchRequested()
}

Java

@Override
public boolean onSearchRequested() {
    pauseSomeStuff();
    return super.onSearchRequested();
}

如果用户通过点按“返回”按钮取消搜索,则搜索对话框 并且 activity 会重新获得输入焦点。您可以注册以接收通知 搜索对话框关闭时 setOnDismissListener(), setOnCancelListener(), 或者两者兼有您只需要注册 OnDismissListener, 因为每次搜索对话框关闭时都会调用它。通过 OnCancelListener 仅适用于用户明确退出搜索对话框的事件, 它在执行搜索时不会被调用。在执行搜索时, 搜索对话框会自动消失。

如果当前 activity 不是可搜索 activity,则常规 activity activity 生命周期事件会在用户执行 search - 当前 activity 会收到 onPause(),如下文所述 简介 activity。不过,如果当前 activity 是可搜索 activity, 则会出现以下两种情况之一:

  • 默认情况下,可搜索 Activity 会收到 带有 onCreate() 调用的 ACTION_SEARCH intent, 并且新 activity 实例会置于 activity 顶部 堆栈。现在,在 因此点按“返回”按钮会返回到上一个 可搜索 activity 实例,而不是退出可搜索 activity 活动。
  • 如果您将 android:launchMode 设置为 "singleTop", 那么可搜索 activity 会收到 ACTION_SEARCH intent ,其中包含以下电话号码: onNewIntent(Intent), 传递新的 ACTION_SEARCH intent。例如,以下是 您可以处理这种情况,即可搜索 activity 的启动模式 为 "singleTop"

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.search)
        handleIntent(intent)
    }
    
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        handleIntent(intent)
    }
    
    private fun handleIntent(intent: Intent) {
        if (Intent.ACTION_SEARCH == intent.action) {
            intent.getStringExtra(SearchManager.QUERY)?.also { query ->
                doMySearch(query)
            }
        }
    }

    Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);
        handleIntent(getIntent());
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(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);
        }
    }

    与上一节中的示例代码相比, 执行搜索时,处理 搜索 intent 现在位于 handleIntent() 方法中, onCreate()onNewIntent() 可以执行它。

    当系统调用 onNewIntent(Intent) 时,activity 不会 因此 getIntent() 方法返回的 intent 与通过 onCreate() 接收的 intent 相同。 因此,您必须调用 setIntent(Intent) onNewIntent(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 Bundle, 包含在 ACTION_SEARCH intent 中。

如需将此类数据传递给可搜索 activity,请替换 onSearchRequested() 方法,用户可以从中 执行搜索,创建包含其他数据的 Bundle,以及 致电 startSearch() 激活搜索对话框。例如:

Kotlin

override fun onSearchRequested(): Boolean {
    val appData = Bundle().apply {
        putBoolean(JARGON, true)
    }
    startSearch(null, false, appData, false)
    return true
}

Java

@Override
public boolean onSearchRequested() {
     Bundle appData = new Bundle();
     appData.putBoolean(SearchableActivity.JARGON, true);
     startSearch(null, false, appData, false);
     return true;
 }

如果返回 true,则表示您已成功处理了此回调事件,并且 调用 startSearch() 以激活搜索对话框。在用户之后 提交查询后,系统会将该查询连同数据一起传递到可搜索 Activity。 。您可以从 APP_DATA 中提取这些额外的数据。 Bundle 来优化搜索,如以下示例所示:

Kotlin

val jargon: Boolean = intent.getBundleExtra(SearchManager.APP_DATA)?.getBoolean(JARGON) ?: false

Java

Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
    boolean jargon = appData.getBoolean(SearchableActivity.JARGON);
}
<ph type="x-smartling-placeholder">

使用搜索微件

显示应用顶部栏中的搜索视图的图片

图 1. SearchViewwidget 应用栏中的操作视图。

搜索微件提供的功能与搜索对话框相同。它 在用户执行搜索时启动相应的 Activity,并且它可以 提供搜索建议并执行语音搜索。如果无法选择 您将搜索微件放在应用栏中,也可以将搜索 widget 放置在 activity 布局中的某个位置。

<ph type="x-smartling-placeholder">

配置搜索微件

创建 搜索配置可搜索的活动,启用辅助搜索 调用 SearchView setSearchableInfo() 并将代表应用的 SearchableInfo 对象 可搜索配置。

您可以通过调用SearchableInfo getSearchableInfo() 已开启 SearchManager

例如,如果您将 SearchView 用作 应用栏中,在 onCreateOptionsMenu() 回调,如以下示例所示:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    // Inflate the options menu from XML.
    val inflater = menuInflater
    inflater.inflate(R.menu.options_menu, menu)

    // Get the SearchView and set the searchable configuration.
    val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
    (menu.findItem(R.id.menu_search).actionView as SearchView).apply {
        // Assumes current activity is the searchable activity.
        setSearchableInfo(searchManager.getSearchableInfo(componentName))
        setIconifiedByDefault(false) // Don't iconify the widget. Expand it by default.
    }

    return true
}

Java

@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); // Don't iconify the widget. Expand it by default.

    return true;
}

搜索微件现已配置完毕,系统会提供搜索查询 添加到可搜索的活动中。您还可以 搜索建议

<ph type="x-smartling-placeholder">

如需详细了解应用栏中的操作视图,请参阅 使用操作视图和操作 提供商

搜索微件的其他功能

SearchView widget 提供了一些其他功能, 可能想要:

提交按钮
默认情况下,系统没有提供用于提交搜索查询的按钮,因此用户必须 按键盘上的回车键启动搜索。您 可以添加“提交”按钮 setSubmitButtonEnabled(true)
搜索建议的查询优化
启用搜索建议后,您通常希望用户选择 但他们可能还需要优化建议的搜索查询 您可以在每条建议旁边添加一个按钮,用于插入该建议 ,以便用户通过调用 setQueryRefinementEnabled(true)
能够切换搜索框的可见性
默认情况下,搜索微件会“图标化”也就是说 只能用一个搜索图标(放大镜)来表示。它会扩展为 在用户点按图标时显示搜索框。如上例所示 您可以通过调用 setIconifiedByDefault(false)。 您还可以通过调用 setIconified()

SearchView 类中还有其他几个 API 您可以自定义搜索微件。但其中的大多数选项 自行处理所有用户输入,而不是使用 Android 系统来提供 搜索查询并显示搜索建议。

同时使用 widget 和对话框

如果您将搜索微件作为 操作视图并启用 通过将它设置为在有空间的情况下显示在应用栏中 android:showAsAction="ifRoom",那么搜索 widget 可能会 不会显示为操作视图相反,菜单项可能会显示在溢出菜单中 菜单。例如,当您的应用在较小的屏幕上运行时 应用栏中有足够的空间来显示搜索微件以及其他操作 项或导航元素,使菜单项出现在溢出菜单中 菜单。放置在溢出菜单中后,该项将像普通菜单一样运作 项,并且不会显示操作视图(即搜索 widget)。

要处理这种情况,您需要附加搜索微件的菜单项 当用户从溢出菜单中选择搜索对话框时,必须激活该对话框。 为此,请实施 onOptionsItemSelected() 用于处理“搜索”菜单项,并通过调用 onSearchRequested()

如需详细了解应用栏中的项的工作原理以及如何处理 请参阅 添加应用栏

添加语音搜索

您可以通过以下方法向搜索对话框或搜索微件添加语音搜索功能: 将 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 指定 语音搜索按钮必须启动一个识别器,用于返回 将转写文本发送到可搜索 activity。

您可以提供其他属性来指定语音搜索行为 例如预期的语言和要返回的结果数上限。请参阅 搜索配置参考,详细了解 了解可用属性的相关信息。

<ph type="x-smartling-placeholder">

添加搜索建议

搜索对话框和搜索微件都可以提供搜索建议 在 Android 系统的协助下由系统管理 建议列表,并在用户选择 建议。

您可以提供两种类型的搜索建议:

近期查询搜索建议
这些建议是用户以前用作搜索的字词 查询。请参阅添加 自定义搜索建议
自定义搜索建议
这些是您通过自己的数据源提供的搜索建议, 帮助用户立即选择正确的拼写字词或搜索内容 。请参阅添加自定义搜索 建议