Cómo crear una interfaz de búsqueda

Cuando estés listo para agregar la funcionalidad de búsqueda a tu app, Android te ayuda a implementar la interfaz de usuario con un diálogo de búsqueda que aparece en la parte superior de la ventana de actividad o un widget de búsqueda que puedes insertar en el diseño. Tanto el diálogo como el widget pueden entregar la búsqueda del usuario a una actividad específica de tu app. De esta manera, el usuario puede iniciar una búsqueda desde cualquier actividad en la que esté disponible el diálogo o widget de búsqueda, y el sistema inicia la actividad adecuada para realizar la búsqueda y presentar los resultados.

Otras funciones disponibles para el diálogo y el widget de búsqueda incluyen las siguientes:

  • Búsqueda por voz
  • Sugerencias de búsqueda basadas en consultas recientes
  • Sugerencias de búsqueda que coinciden con los resultados reales en los datos de tu app

En este documento, se muestra cómo configurar tu app para proporcionar una interfaz de búsqueda asistida por el sistema Android para entregar búsquedas mediante el diálogo o el widget de búsqueda.

Recursos relacionados:

Conceptos básicos

Antes de comenzar, decide si quieres implementar la interfaz de búsqueda mediante el diálogo o el widget de búsqueda. Proporcionan las mismas funciones de búsqueda, pero de maneras ligeramente diferentes:

  • El diálogo de búsqueda es un componente de IU controlado por el sistema Android. Cuando el usuario lo activa, el diálogo de búsqueda aparece en la parte superior de la actividad.

    El sistema Android controla todos los eventos en el diálogo de búsqueda. Cuando el usuario envía una consulta, el sistema la entrega a la actividad que especifiques para que se encargue de las búsquedas. El diálogo también puede proporcionar sugerencias de búsqueda mientras el usuario escribe.

  • El widget de búsqueda es una instancia de SearchView que puedes colocar en cualquier lugar del diseño. De forma predeterminada, el widget de búsqueda se comporta como un widget EditText estándar y no hace nada, pero puedes configurarlo para que el sistema Android maneje todos los eventos de entrada, envíe consultas a la actividad adecuada y proporcione sugerencias de búsqueda, al igual que el diálogo de búsqueda.

Cuando el usuario ejecuta una búsqueda desde el diálogo o un widget de búsqueda, el sistema crea un Intent y almacena la consulta del usuario en él. Luego, el sistema inicia la actividad que declaras que controla las búsquedas (la "actividad de búsqueda") y le entrega el intent. Para configurar tu app para este tipo de búsqueda asistida, necesitas lo siguiente:

  • Una configuración de búsqueda
    Es un archivo en formato XML que establece algunos parámetros de configuración para el diálogo o el widget de búsqueda. Incluye parámetros de configuración para funciones como la búsqueda por voz, las sugerencias de búsqueda y el texto de sugerencias para el cuadro de búsqueda.
  • Una actividad de búsqueda
    El Activity que recibe la búsqueda, busca en tus datos y muestra los resultados de la búsqueda.
  • Una interfaz de búsqueda proporcionada por cualquiera de los siguientes proveedores:
    • Diálogo de búsqueda
      De forma predeterminada, el diálogo de búsqueda está oculto. Aparece en la parte superior de la pantalla cuando llamas a onSearchRequested() cuando el usuario presiona el botón Buscar.
    • Un widget SearchView
      Usar el widget de búsqueda te permite colocar el cuadro de búsqueda en cualquier parte de tu actividad, incluso como una vista de acción en la barra de la app.

En el resto de este documento, se muestra cómo crear la configuración y la actividad de búsqueda, y cómo implementar una interfaz de búsqueda con el diálogo o el widget de búsqueda.

Cómo crear una configuración de búsqueda

Lo primero que necesitas es un archivo en formato XML denominado configuración de búsqueda. Configura ciertos aspectos de la IU del diálogo o widget de búsqueda y define el comportamiento de funciones como las sugerencias y la búsqueda por voz. Tradicionalmente, este archivo se llama searchable.xml y debe guardarse en el directorio del proyecto res/xml/.

El archivo de configuración de búsqueda debe incluir el elemento <searchable> como su nodo raíz y especificar uno o más atributos, como se muestra en el siguiente ejemplo:

<?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>

El atributo android:label es el único atributo requerido. Apunta a un recurso de cadenas, que debe ser el nombre de la app. Esta etiqueta no estará visible para el usuario hasta que habilites las sugerencias de búsqueda para el cuadro de búsqueda rápida, momento en el cual la etiqueta estará visible en la lista de elementos de búsqueda en la configuración del sistema.

Aunque no es obligatorio, te recomendamos que siempre incluyas el atributo android:hint, que proporciona una string de sugerencia en el cuadro de búsqueda antes de que los usuarios ingresen una consulta. La sugerencia es importante porque proporciona pistas importantes a los usuarios sobre lo que pueden buscar.

El elemento <searchable> acepta muchos otros atributos. Sin embargo, no necesitarás la mayoría de los atributos hasta que agregues funciones como las sugerencias de búsqueda y la búsqueda por voz. Para obtener información detallada sobre el archivo de configuración de búsqueda, consulta el documento de referencia sobre la configuración de búsqueda.

Cómo crear una actividad de búsqueda

Una actividad de búsqueda es la Activity de tu app que realiza búsquedas basadas en una cadena de consulta y presenta los resultados de la búsqueda.

Cuando el usuario ejecuta una búsqueda en el diálogo o widget de búsqueda, el sistema inicia la actividad de búsqueda y le entrega la búsqueda en un Intent con la acción ACTION_SEARCH. La actividad de búsqueda recupera la consulta del extra QUERY del intent, busca en tus datos y presenta los resultados.

Debido a que puedes incluir el diálogo o el widget de búsqueda en cualquier otra actividad de tu app, el sistema debe saber cuál es la actividad de búsqueda para poder entregar correctamente la búsqueda. Por lo tanto, primero declara la actividad de búsqueda en el archivo de manifiesto de Android.

Cómo declarar una actividad de búsqueda

Si aún no tienes uno, crea un Activity que realice búsquedas y presente resultados. Aún no es necesario que implementes la funcionalidad de búsqueda; solo crea una actividad que puedas declarar en el manifiesto. Dentro del elemento <activity> del manifiesto, haz lo siguiente:

  1. Declara la actividad para que acepte el intent ACTION_SEARCH en un elemento <intent-filter>.
  2. Especifica la configuración de búsqueda que se usará en un elemento <meta-data>.

Esto se muestra en el siguiente ejemplo:

<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>

El elemento <meta-data> debe incluir el atributo android:name con un valor de "android.app.searchable" y el atributo android:resource con una referencia al archivo de configuración de búsqueda. En el ejemplo anterior, se refiere al archivo res/xml/searchable.xml.

Realizar una búsqueda

Después de declarar la actividad de búsqueda en el manifiesto, sigue este procedimiento para realizar una búsqueda en esa actividad:

  1. Recibe la consulta.
  2. Busca en tus datos.
  3. Presenta los resultados.

Recibe la consulta

Cuando un usuario ejecuta una búsqueda desde el diálogo o widget de búsqueda, el sistema inicia la actividad de búsqueda y le envía un intent ACTION_SEARCH. Este intent lleva la búsqueda en la string adicional QUERY. Busca este intent cuando comience la actividad y extrae la cadena. Por ejemplo, a continuación, se muestra cómo puedes obtener la búsqueda cuando comienza la actividad de búsqueda:

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);
    }
}

La cadena QUERY siempre se incluye con el intent ACTION_SEARCH. En el ejemplo anterior, la consulta se recupera y se pasa a un método doMySearch() local donde se realiza la operación de búsqueda real.

Buscar en tus datos

El proceso de almacenar y buscar tus datos es exclusivo de tu app. Los datos se pueden almacenar y buscar de muchas maneras, y en este documento no se muestra cómo hacerlo. Considera cómo almacenas y buscas tus datos en función de tus necesidades y el formato de tus datos. Las siguientes son sugerencias que podrías aplicar:

  • Si tus datos se almacenan en una base de datos SQLite en el dispositivo, realizar una búsqueda en el texto completo (mediante FTS3, en lugar de una consulta LIKE) puede proporcionar una búsqueda más sólida en los datos de texto y puede producir resultados mucho más rápido. Consulta sqlite.org para obtener información sobre FTS3 y la clase SQLiteDatabase para obtener información sobre SQLite en Android.
  • Si tus datos se almacenan en línea, el rendimiento de búsqueda percibido podría estar inhibido por la conexión de datos del usuario. Es posible que desees mostrar un indicador de progreso hasta que aparezca tu búsqueda. Consulta android.net para obtener una referencia de las APIs de red y ProgressBar para obtener información sobre cómo mostrar un indicador de progreso.

Presenta los resultados

Sin importar dónde se encuentren tus datos y cómo los busques, te recomendamos que muestres los resultados de la búsqueda a la actividad de búsqueda con un Adapter. De esta manera, puedes presentar todos los resultados de la búsqueda en una RecyclerView. Si tus datos provienen de una consulta de base de datos SQLite, puedes aplicar los resultados a un RecyclerView usando un CursorAdapter. Si tus datos vienen en un formato diferente, puedes crear una extensión de BaseAdapter.

Un Adapter vincula cada elemento de un conjunto de datos en un objeto View. Cuando se aplica el Adapter a una RecyclerView, cada dato se inserta como una vista individual en la lista. Adapter es solo una interfaz, por lo que se necesitan implementaciones como CursorAdapter, para vincular datos desde un Cursor. Si ninguna de las implementaciones existentes funciona para tus datos, puedes implementar la tuya desde BaseAdapter.

Cómo usar el diálogo de búsqueda

El diálogo de búsqueda proporciona un cuadro de búsqueda flotante en la parte superior de la pantalla, con el ícono de la app a la izquierda. El diálogo de búsqueda puede proporcionar sugerencias de búsqueda a medida que el usuario escribe. Cuando el usuario ejecuta una búsqueda, el sistema envía la búsqueda a una actividad de búsqueda que realiza la búsqueda.

De forma predeterminada, el diálogo de búsqueda siempre está oculto hasta que el usuario lo activa. Tu app puede activar el diálogo de búsqueda llamando a onSearchRequested(). Sin embargo, este método no funcionará hasta que habilites el diálogo de búsqueda para la actividad.

Para permitir que el diálogo de búsqueda realice búsquedas, indica al sistema qué actividad de búsqueda debe recibir consultas en ese diálogo. Por ejemplo, en la sección anterior sobre cómo crear una actividad de búsqueda, se crea una actividad de búsqueda llamada SearchableActivity. Si deseas que una actividad separada, como una llamada OtherActivity, muestre el diálogo de búsqueda y entregue búsquedas a SearchableActivity, declara en el manifiesto que SearchableActivity es la actividad de búsqueda que se usará para el diálogo de búsqueda en OtherActivity.

Para declarar la actividad de búsqueda del diálogo de búsqueda de una actividad, agrega un elemento <meta-data> dentro del elemento <activity> de la actividad correspondiente. El elemento <meta-data> debe incluir el atributo android:value que especifica el nombre de clase de la actividad de búsqueda y el atributo android:name con un valor de "android.app.default_searchable".

Por ejemplo, esta es la declaración para una actividad de búsqueda, SearchableActivity, y otra actividad, OtherActivity, que usa SearchableActivity para realizar búsquedas ejecutadas desde su diálogo de búsqueda:

<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>

Como OtherActivity ahora incluye un elemento <meta-data> para declarar qué actividad de búsqueda usar para las búsquedas, la actividad habilita el diálogo de búsqueda. Si bien el usuario está en esta actividad, el método onSearchRequested() activa el diálogo de búsqueda. Cuando el usuario ejecuta la búsqueda, el sistema inicia SearchableActivity y le entrega el intent ACTION_SEARCH.

Si quieres que todas las actividades de tu app proporcionen el diálogo de búsqueda, inserta el elemento <meta-data> anterior como elemento secundario del elemento <application>, en lugar de cada <activity>. De esta manera, cada actividad hereda el valor, proporciona el diálogo de búsqueda y entrega búsquedas a la misma actividad de búsqueda. Si tienes varias actividades de búsqueda, puedes anular la predeterminada si colocas una declaración <meta-data> diferente en las actividades individuales.

Con el diálogo de búsqueda habilitado para tus actividades, tu app está lista para realizar búsquedas.

Cómo invocar el diálogo de búsqueda

Aunque algunos dispositivos proporcionan un botón de búsqueda exclusivo, el comportamiento del botón puede variar según el dispositivo, y muchos no lo proporcionan. Por lo tanto, cuando uses el diálogo de búsqueda, deberás proporcionar un botón de búsqueda en la IU que lo active llamando a onSearchRequested().

Por ejemplo, agrega un botón de búsqueda en tu menú de opciones o un diseño de la IU que llame a onSearchRequested().

También puedes habilitar la función "escribir para buscar", que activa el diálogo de búsqueda cuando el usuario comienza a escribir con el teclado. Las combinaciones de teclas se insertan en el diálogo de búsqueda. Puedes habilitar la función de escribir para buscar en tu actividad llamando a setDefaultKeyMode, o a DEFAULT_KEYS_SEARCH_LOCAL, durante el método onCreate() de tu actividad.

El impacto del diálogo de búsqueda en el ciclo de vida de la actividad

El diálogo de búsqueda es un Dialog que flota en la parte superior de la pantalla. No provoca ningún cambio en la pila de actividades, por lo que, cuando aparece el diálogo de búsqueda, no se llama a ningún método de ciclo de vida, como onPause(). La actividad pierde el foco de entrada porque se pasa al diálogo de búsqueda.

Si quieres recibir una notificación cuando el diálogo de búsqueda esté activado, anula el método onSearchRequested(). Cuando el sistema llama a este método, es una indicación de que tu actividad pierde el foco de entrada en el diálogo de búsqueda, de modo que puedes hacer cualquier trabajo apropiado para el evento, como pausar un juego. A menos que pases datos del contexto de búsqueda, que se analizan en otra sección de este documento, finaliza el método llamando a la implementación de la superclase:

Kotlin

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

Java

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

Si el usuario cancela la búsqueda presionando el botón Atrás, se cierra el diálogo de búsqueda y la actividad vuelve a obtener el foco de entrada. Puedes registrarte para recibir una notificación cuando se cierre el diálogo de búsqueda con setOnDismissListener(), setOnCancelListener() o ambos. Solo debes registrar el OnDismissListener, ya que se llama cada vez que se cierra el diálogo de búsqueda. El OnCancelListener solo corresponde a eventos en los que el usuario sale explícitamente del diálogo de búsqueda, por lo que no se llama cuando se ejecuta una búsqueda. Cuando se ejecuta la búsqueda, el diálogo de búsqueda desaparece automáticamente.

Si la actividad actual no es la actividad de búsqueda, los eventos del ciclo de vida de la actividad normal se activan cuando el usuario ejecuta una búsqueda. La actividad actual recibe onPause(), como se describe en Introducción a las actividades. Sin embargo, si la actividad actual es la de búsqueda, ocurrirá una de estas dos cosas:

  • De forma predeterminada, la actividad que se puede buscar recibe el intent ACTION_SEARCH con una llamada a onCreate(), y una instancia nueva de la actividad se lleva a la parte superior de la pila de actividades. Ahora hay dos instancias de tu actividad de búsqueda en la pila de actividades, por lo que, si presionas el botón Atrás, regresarás a la instancia anterior de la actividad de búsqueda, en lugar de salir de esa actividad.
  • Si configuras android:launchMode como "singleTop", la actividad de búsqueda recibe el intent ACTION_SEARCH con una llamada a onNewIntent(Intent) y pasa el nuevo intent ACTION_SEARCH. Por ejemplo, a continuación, se muestra cómo podrías manejar este caso, en el que el modo de inicio de la actividad de búsqueda es "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);
        }
    }
    

    En comparación con el código de ejemplo de la sección sobre cómo realizar una búsqueda, todo el código para procesar el intent de búsqueda ahora se encuentra en el método handleIntent(), de modo que onCreate() y onNewIntent() pueden ejecutarlo.

    Cuando el sistema llama a onNewIntent(Intent), la actividad no se reinicia, por lo que el método getIntent() muestra el mismo intent que se recibe con onCreate(). Es por eso que debes llamar a setIntent(Intent) dentro de onNewIntent(Intent), de modo que se actualice el intent que guarda la actividad en caso de que llames a getIntent() en el futuro.

La segunda situación, que usa el modo de lanzamiento "singleTop", suele ser preferible, ya que, después de realizar una búsqueda, el usuario puede realizar búsquedas adicionales, y no quieres que tu app cree varias instancias de la actividad de búsqueda. Te recomendamos establecer la actividad de búsqueda en el modo de inicio "singleTop" en el manifiesto de la app, como se muestra en el siguiente ejemplo:

<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>

Cómo pasar datos del contexto de búsqueda

En algunos casos, puedes realizar las mejoras necesarias en la búsqueda dentro de la actividad de búsqueda para cada búsqueda realizada. Sin embargo, si deseas definir mejor tus criterios de búsqueda en función de la actividad desde la cual el usuario realiza una búsqueda, puedes proporcionar datos adicionales en el intent que el sistema envía a la actividad de búsqueda. Puedes pasar los datos adicionales en el Bundle de APP_DATA, que se incluye en el intent ACTION_SEARCH.

Para pasar este tipo de datos a tu actividad de búsqueda, anula el método onSearchRequested() para la actividad desde la que el usuario puede realizar una búsqueda, crea un Bundle con los datos adicionales y llama a startSearch() para activar el diálogo de búsqueda. Por ejemplo:

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;
 }

Si se muestra verdadero, significa que controlas correctamente este evento de devolución de llamada y llamas a startSearch() para activar el diálogo de búsqueda. Después de que el usuario envía una consulta, esta se entrega a la actividad de búsqueda junto con los datos que agregas. Puedes extraer los datos adicionales de Bundle de APP_DATA para definir mejor la búsqueda, como se muestra en el siguiente ejemplo:

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);
}

Usa el widget de búsqueda

Imagen que muestra una vista de búsqueda en la barra superior de la app

Figura 1: El widget SearchView como una vista de acción en la barra de la app

El widget de búsqueda proporciona la misma funcionalidad que el diálogo de búsqueda. Inicia la actividad correspondiente cuando el usuario ejecuta una búsqueda y puede proporcionar sugerencias de búsqueda y realizar búsquedas por voz. Si no es una opción para ti colocar el widget de búsqueda en la barra de la app, puedes colocarlo en algún lugar del diseño de la actividad.

Configura el widget de búsqueda

Después de crear una configuración de búsqueda y una actividad de búsqueda, habilita la búsqueda asistida para cada SearchView llamando a setSearchableInfo() y pasándole el objeto SearchableInfo que representa la configuración de búsqueda.

Para obtener una referencia al SearchableInfo, llama a getSearchableInfo() en SearchManager.

Por ejemplo, si usas un objeto SearchView como vista de acción en la barra de la app, habilita el widget durante la devolución de llamada onCreateOptionsMenu(), como se muestra en el siguiente ejemplo:

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;
}

El widget de búsqueda ya está configurado y el sistema entrega consultas a tu actividad de búsqueda. También puedes habilitar las sugerencias de búsqueda para el widget de búsqueda.

Para obtener más información sobre las vistas de acciones en la barra de la app, consulta Cómo usar vistas y proveedores de acciones.

Otras funciones del widget de búsqueda

El widget SearchView proporciona algunas funciones adicionales que tal vez desees:

Un botón Enviar
De forma predeterminada, no hay un botón para enviar una búsqueda, por lo que el usuario debe presionar la tecla Intro en el teclado para iniciar una búsqueda. Puedes agregar un botón "enviar" llamando a setSubmitButtonEnabled(true).
Mejora en la definición de consultas para sugerencias de búsqueda
Cuando habilitas las sugerencias de búsqueda, por lo general, esperas que los usuarios seleccionen una sugerencia, pero es posible que también quieran definir mejor la búsqueda sugerida. Puedes agregar un botón junto a cada sugerencia que inserte la sugerencia en el cuadro de búsqueda para que el usuario la defina mejor llamando a setQueryRefinementEnabled(true).
La capacidad de activar o desactivar la visibilidad del cuadro de búsqueda
De forma predeterminada, el widget de búsqueda está “iconificado”, lo que significa que solo está representado por un ícono de búsqueda: una lupa. Se expande para mostrar el cuadro de búsqueda cuando el usuario presiona el ícono. Como se muestra en el ejemplo anterior, puedes mostrar el cuadro de búsqueda de forma predeterminada llamando a setIconifiedByDefault(false). También puedes llamar a setIconified() para alternar la apariencia del widget de búsqueda.

Hay varias otras APIs en la clase SearchView que te permiten personalizar el widget de búsqueda. Sin embargo, la mayoría de ellas se usan solo cuando tú controlas todas las entradas de los usuarios, en lugar de usar el sistema Android para enviar búsquedas y mostrar sugerencias de búsqueda.

Usa el widget y el diálogo

Si insertas el widget de búsqueda en la barra de la app como una vista de acción y lo habilitas para que aparezca en la barra de la app si hay espacio (estableciendo android:showAsAction="ifRoom"), es posible que el widget de búsqueda no aparezca como una vista de acción. En su lugar, un elemento de menú puede aparecer en el menú ampliado. Por ejemplo, cuando tu app se ejecuta en una pantalla más pequeña, es posible que no haya suficiente espacio en la barra de la app para mostrar el widget de búsqueda junto con otros elementos de acción o de navegación, por lo que el elemento de menú aparece en el menú ampliado. Cuando se coloca en el menú ampliado, el elemento funciona como un elemento de menú común y no muestra la vista de acción, es decir, el widget de búsqueda.

Para manejar esta situación, el elemento de menú al que adjuntas el widget de búsqueda debe activar el diálogo de búsqueda cuando el usuario lo selecciona en el menú ampliado. Para que esto suceda, implementa onOptionsItemSelected() para controlar el elemento de menú "Buscar" y llama a onSearchRequested() para abrir el diálogo de búsqueda.

Para obtener más información sobre cómo funcionan los elementos de la barra de la app y cómo controlar esta situación, consulta Cómo agregar la barra de la app.

Cómo agregar la búsqueda por voz

Puedes agregar la funcionalidad de búsqueda por voz al diálogo o widget de búsqueda agregando el atributo android:voiceSearchMode a la configuración de búsqueda. Esto agrega un botón de búsqueda por voz que inicia un mensaje de voz. Cuando el usuario termina de hablar, la búsqueda transcrita se envía a tu actividad de búsqueda.

Esto se muestra en el siguiente ejemplo:

<?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>

Se requiere el valor showVoiceSearchButton para habilitar la búsqueda por voz. El segundo valor, launchRecognizer, especifica que el botón de búsqueda por voz debe iniciar un recognizer que muestre el texto transcrito a la actividad de búsqueda.

Puedes proporcionar atributos adicionales para especificar el comportamiento de la búsqueda por voz, como el idioma esperado y la cantidad máxima de resultados que se mostrarán. Consulta la referencia Configuración de búsqueda para obtener más información sobre los atributos disponibles.

Agrega sugerencias de búsqueda

Tanto el diálogo como el widget de búsqueda pueden proporcionar sugerencias de búsqueda a medida que el usuario escribe, con la ayuda del sistema Android. El sistema administra la lista de sugerencias y controla el evento cuando el usuario selecciona una sugerencia.

Puedes proporcionar dos tipos de sugerencias de búsqueda:

Sugerencias de búsquedas recientes
Estas sugerencias son palabras que el usuario utilizó anteriormente como búsquedas en tu app. Consulta Cómo agregar sugerencias de búsqueda personalizadas para obtener más información.
Sugerencias de búsqueda personalizadas
Estas son sugerencias de búsqueda que proporcionas desde tu propia fuente de datos para ayudar a los usuarios a seleccionar inmediatamente la ortografía o el elemento correctos que están buscando. Consulta Cómo agregar sugerencias de búsqueda personalizadas para obtener más información.