Cómo agregar sugerencias de consultas recientes

Cuando usas el diálogo o el widget de búsqueda de Android, puedes proporcionar sugerencias de búsqueda basadas en búsquedas recientes. Por ejemplo, si un usuario buscó previamente "cachorros", esa consulta aparece como una sugerencia una vez que comienza a escribir la misma consulta. En la figura 1, se muestra un ejemplo de un diálogo de búsqueda con sugerencias de consultas recientes.

Antes de comenzar, debes implementar el diálogo o un widget de búsqueda para búsquedas básicas en la aplicación. Si no lo hiciste, consulta Cómo crear una interfaz de búsqueda.

Conceptos básicos

Figura 1: Captura de pantalla de un diálogo de búsqueda con sugerencias de consultas recientes

Las sugerencias de consultas recientes son búsquedas guardadas. Cuando el usuario selecciona una de las sugerencias, la actividad de búsqueda recibe un intent ACTION_SEARCH con la sugerencia como la búsqueda, que ya administra la actividad de búsqueda (como se describe en Cómo crear una interfaz de búsqueda).

Para proporcionar sugerencias de consultas recientes, debes hacer lo siguiente:

  • Implementa una actividad de búsqueda como se describe en Cómo crear una interfaz de búsqueda.
  • Crea un proveedor de contenido que extienda SearchRecentSuggestionsProvider y decláralo en el manifiesto de tu aplicación.
  • Modifica la configuración de búsqueda con información sobre el proveedor de contenido que proporciona sugerencias de búsqueda.
  • Guarda consultas en tu proveedor de contenido cada vez que se ejecute una búsqueda.

Así como el sistema Android muestra el diálogo de búsqueda, también muestra las sugerencias de búsqueda debajo del diálogo o widget de búsqueda. Todo lo que debes hacer es proporcionar una fuente desde la cual el sistema pueda recuperar sugerencias.

Cuando el sistema identifica que la actividad se puede buscar y proporciona sugerencias de búsqueda, se lleva a cabo el siguiente procedimiento no bien el usuario comienza a escribir una consulta:

  1. El sistema toma el texto de la búsqueda (lo que se escribió hasta el momento) y realiza una consulta al proveedor de contenido que contiene tus sugerencias.
  2. Tu proveedor de contenido muestra un Cursor que apunta a todas las sugerencias que coinciden con el texto de la búsqueda.
  3. El sistema muestra la lista de sugerencias que proporciona el cursor.

Una vez que se muestran las sugerencias de consultas recientes, puede ocurrir lo siguiente:

  • Si el usuario escribe otra palabra clave o cambia la consulta de alguna forma, se repiten los pasos anteriores y se actualiza la lista de sugerencias.
  • Si el usuario ejecuta la búsqueda, se ignoran las sugerencias y se entrega la búsqueda a la actividad de búsqueda con el intent ACTION_SEARCH normal.
  • Si el usuario selecciona una sugerencia, se entrega un intent ACTION_SEARCH a la actividad de búsqueda y se utiliza el texto sugerido como la consulta.

La clase SearchRecentSuggestionsProvider que extiendes para el proveedor de contenido realiza automáticamente el trabajo que se describió antes, por lo que, en realidad, es muy poco el código que hay que escribir.

Cómo crear un proveedor de contenido

El proveedor de contenido que necesitas para sugerencias de consultas recientes debe ser una implementación de SearchRecentSuggestionsProvider. Esta clase hace prácticamente todo por ti. Lo único que tienes que hacer es escribir un constructor de clase que ejecute una línea de código.

Por ejemplo, a continuación, se incluye una implementación completa de un proveedor de contenido para sugerencias de consultas recientes:

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

La llamada a setupSuggestions() transmite el nombre de la autoridad de búsqueda y un modo de base de datos. La autoridad de búsqueda puede ser una string única cualquiera, pero la práctica recomendada es usar un nombre completo para el proveedor de contenido (nombre del paquete seguido del nombre de la clase del proveedor; por ejemplo, "com.example.MySuggestionProvider"). El modo de base de datos debe incluir DATABASE_MODE_QUERIES y opcionalmente puede incluir DATABASE_MODE_2LINES, que agrega otra columna a la tabla de sugerencias que permite proporcionar una segunda línea de texto con cada sugerencia. Por ejemplo, si deseas proporcionar dos líneas en cada sugerencia, haz lo siguiente:

Kotlin

    const val MODE: Int = DATABASE_MODE_QUERIES or DATABASE_MODE_2LINES
    

Java

    public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;
    

Ahora, declara el proveedor de contenido en el manifiesto de la aplicación con la misma string de autoridad utilizada en tu clase SearchRecentSuggestionsProvider (y en la configuración de búsqueda). Por ejemplo:

    <application>
        <provider android:name=".MySuggestionProvider"
                  android:authorities="com.example.MySuggestionProvider" />
        ...
    </application>
    

Cómo modificar la configuración de búsqueda

Para configurar el sistema a fin de utilizar tu proveedor de sugerencias, debes agregar los atributos android:searchSuggestAuthority y android:searchSuggestSelection al elemento <searchable> en el archivo de configuración de búsqueda. Por 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"
        android:searchSuggestAuthority="com.example.MySuggestionProvider"
        android:searchSuggestSelection=" ?" >
    </searchable>
    

El valor de android:searchSuggestAuthority debe ser un nombre completo para tu proveedor de contenido que coincida exactamente con la autoridad utilizada en el proveedor de contenido (la string AUTHORITY en el ejemplo anterior).

El valor de android:searchSuggestSelection debe ser un solo signo de interrogación, precedido por un espacio (" ?"), que es un marcador de posición para el argumento de selección de SQLite (el cual se reemplaza automáticamente por el texto de consulta que ingresa el usuario).

Cómo guardar consultas

Para propagar la colección de consultas recientes, agrega cada consulta recibida por la actividad de búsqueda a tu SearchRecentSuggestionsProvider. Para ello, crea una instancia de SearchRecentSuggestions y llama a saveRecentQuery() cada vez que la actividad de búsqueda reciba una consulta. Por ejemplo, a continuación, se indica cómo puedes guardar la consulta durante el método onCreate() de tu actividad:

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

El constructor SearchRecentSuggestionsProvider requiere la misma autoridad y el mismo modo de base de datos declarados por el proveedor de contenido.

El método saveRecentQuery() toma la cadena de consulta de búsqueda como el primer parámetro y, opcionalmente, una segunda string para incluir como la segunda línea de la sugerencia (o que queda vacía). El segundo parámetro solo se utiliza si habilitaste el modo de dos líneas para las sugerencias de búsqueda con DATABASE_MODE_2LINES. Si lo habilitaste, el texto de la consulta también se compara con esta segunda línea cuando el sistema busca sugerencias coincidentes.

Cómo borrar los datos de sugerencia

Para proteger la privacidad del usuario, siempre debes proporcionar una forma para borrar las sugerencias de consultas recientes. Para borrar el historial de consultas, llama a clearHistory(). Por ejemplo:

Kotlin

    SearchRecentSuggestions(this, HelloSuggestionsProvider.AUTHORITY, HelloSuggestionsProvider.MODE)
            .clearHistory()
    

Java

    SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
            HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
    suggestions.clearHistory();
    

Ejecuta esto en un elemento de menú, elemento de preferencia o botón de "Borrar historial de búsqueda". También debes proporcionar un diálogo de confirmación para verificar si el usuario desea borrar su historial de búsqueda.