Android: ¿Proporciona sugerencias de búsqueda recientes sin actividad de búsqueda?

Tengo un ActionBar SearchView y soy capaz de hacer búsquedas con él. La documentación de Android no explica cómo implementar sugerencias de búsqueda. No quiero tener una actividad de búsqueda.

Este es mi código de búsqueda:

public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_add_song, menu); final SearchView searchView = (SearchView) menu.findItem(R.id.song_search).getActionView(); searchView.setFocusable(true); searchView.setIconified(false); final AddSongActivity activity = this; searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextChange(String newText) { // Do nothing return true; } @Override public boolean onQueryTextSubmit(String query) { // Clear SearchView searchView.clearFocus(); // Begin Spotify Search TextView notice = (TextView)findViewById(R.id.search_notice); URL url; try { url = new URL("http://ws.spotify.com/search/1/track.json?q=" + URLEncoder.encode(query,"UTF-8")); } catch (MalformedURLException e) { notice.setText("Malformed Search"); notice.setHeight(noticeHeight); return true; } catch (UnsupportedEncodingException e) { notice.setText("Unsupported Encoding. Maybe a problem with your device."); notice.setHeight(noticeHeight); return true; } new SearchDownload(url, activity).execute(); notice.setText("Loading Tracks"); notice.setHeight(noticeHeight); Log.i("infodb","" + noticeHeight); return true; } }); 

Esto funciona para la búsqueda, pero no tengo idea de implementar sugerencias recientes de búsqueda. ¿Cómo voy a hacer esto?

Gracias.

Ok, pasé mi tiempo para esto. Hago mi propia implementación de sugerencia simple desde SQLiteDatabase .

Vamos a crear 3 clases como las siguientes

  1. MainActivity – para la prueba de la sugerencia de SearchView de la base de datos
  2. SuggestionDatabase – esto almacenará su palabra clave de búsqueda reciente.
  3. SuggestionSimpleCursorAdapter – esto es una subclase de SimpleCursorAdapter . Voy a explicar por qué hago esta clase en lugar de usar SimpleCursorAdapter .

Los códigos

 // MainActivity.java public class MainActivity extends Activity implements SearchView.OnQueryTextListener, SearchView.OnSuggestionListener { private SuggestionsDatabase database; private SearchView searchView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); database = new SuggestionsDatabase(this); searchView = (SearchView) findViewById(R.id.searchView1); searchView.setOnQueryTextListener(this); searchView.setOnSuggestionListener(this); } @Override public boolean onSuggestionSelect(int position) { return false; } @Override public boolean onSuggestionClick(int position) { SQLiteCursor cursor = (SQLiteCursor) searchView.getSuggestionsAdapter().getItem(position); int indexColumnSuggestion = cursor.getColumnIndex( SuggestionsDatabase.FIELD_SUGGESTION); searchView.setQuery(cursor.getString(indexColumnSuggestion), false); return true; } @Override public boolean onQueryTextSubmit(String query) { long result = database.insertSuggestion(query); return result != -1; } @Override public boolean onQueryTextChange(String newText) { Cursor cursor = database.getSuggestions(newText); if(cursor.getCount() != 0) { String[] columns = new String[] {SuggestionsDatabase.FIELD_SUGGESTION }; int[] columnTextId = new int[] { android.R.id.text1}; SuggestionSimpleCursorAdapter simple = new SuggestionSimpleCursorAdapter(getBaseContext(), android.R.layout.simple_list_item_1, cursor, columns , columnTextId , 0); searchView.setSuggestionsAdapter(simple); return true; } else { return false; } } } 

Cómo funciona

  1. Cuando el usuario pulsa el botón de búsqueda, se onQueryTextSubmit() y luego se guardará la palabra clave de búsqueda en nuestra base de datos. Digamos que enviamos una palabra clave "Hola"
  2. Si el usuario escribe una cadena por ejemplo "Hel" o "H" en onQueryTextChange() y luego buscaremos esta palabra clave en SQLiteDatabase ( SuggestionDatabase ). Si "Hel" o "H" coincide con "Hola", muestre los resultados de la consulta estableciendo el Cursor devuelto en SuggestionSimpleCursorAdapter y luego configure este adaptador en SearchView . Aquí está la imagen.

Introduzca aquí la descripción de la imagen
3. Por supuesto vamos a tocar la sugerencia que es "Hola", onSuggestionClick(int position) se llamará para eso. Conseguimos el objeto de SQLiteCursor del SQLiteCursor ( SuggestionSimpleCursorAdapter ) y conseguimos el texto de la sugerencia de él, fijamos el texto de la sugerencia en el objeto de SearchView

 SQLiteCursor cursor = (SQLiteCursor) searchView.getSuggestionsAdapter().getItem(position); int indexColumnSuggestion = cursor.getColumnIndex( SuggestionsDatabase.FIELD_SUGGESTION); searchView.setQuery(cursor.getString(indexColumnSuggestion), false); 

Si usamos SimpleCursorAdapter también funciona correctamente, pero digamos que tenemos este escenario

  1. Si ejecutamos este programa en smartphone y escribimos la palabra clave "Hel", la sugerencia aparecerá correctamente.

Introduzca aquí la descripción de la imagen

  1. ¿Qué pasa si giramos la pantalla en el paisaje? Cambiará en modo de pantalla completa y todavía puede escribir la palabra clave.

¿Qué pasará en la sugerencia? Vamos a ver.

Introduzca aquí la descripción de la imagen

¿Ves la extraña sugerencia? ¿Cómo resolvemos eso? convertToString(Cursor cursor) el convertToString(Cursor cursor) que devuelve un CharSequence

  // SuggestionSimpleCursorAdapter.java public class SuggestionSimpleCursorAdapter extends SimpleCursorAdapter { public SuggestionSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); } public SuggestionSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) { super(context, layout, c, from, to, flags); } @Override public CharSequence convertToString(Cursor cursor) { int indexColumnSuggestion = cursor.getColumnIndex(SuggestionsDatabase.FIELD_SUGGESTION); return cursor.getString(indexColumnSuggestion); } } 

Al superar convertToString(Cursor cursor) , aquí está el resultado

Introduzca aquí la descripción de la imagen

Y aquí está la base de datos

 // SuggestionDatabase.java public class SuggestionsDatabase { public static final String DB_SUGGESTION = "SUGGESTION_DB"; public final static String TABLE_SUGGESTION = "SUGGESTION_TB"; public final static String FIELD_ID = "_id"; public final static String FIELD_SUGGESTION = "suggestion"; private SQLiteDatabase db; private Helper helper; public SuggestionsDatabase(Context context) { helper = new Helper(context, DB_SUGGESTION, null, 1); db = helper.getWritableDatabase(); } public long insertSuggestion(String text) { ContentValues values = new ContentValues(); values.put(FIELD_SUGGESTION, text); return db.insert(TABLE_SUGGESTION, null, values); } public Cursor getSuggestions(String text) { return db.query(TABLE_SUGGESTION, new String[] {FIELD_ID, FIELD_SUGGESTION}, FIELD_SUGGESTION+" LIKE '"+ text +"%'", null, null, null, null); } private class Helper extends SQLiteOpenHelper { public Helper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE "+TABLE_SUGGESTION+" ("+ FIELD_ID+" integer primary key autoincrement, "+FIELD_SUGGESTION+" text);"); Log.d("SUGGESTION", "DB CREATED"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } } 

Espero que esta respuesta sea útil para otros programadores mucho. 🙂

En la clase MainActivity de arriba en el onCreate method use este código primero

 AutoCompleteTextView search_text = (AutoCompleteTextView) searchView.findViewById(searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null)); search_text.setThreshold(1); 

Este setThreshold(1) significa que puede buscar el texto de un carácter así ahora.

Mi necesidad era aún más simplista: no necesitaba una base de datos, ya que tenía las sugerencias que muchos querían mostrar contenidas en un ArrayList.

He aquí un ejemplo de implementación:

 import java.util.ArrayList; import android.app.Activity; import android.app.SearchManager; import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.CursorAdapter; import android.widget.SearchView; import android.widget.SearchView.OnQueryTextListener; import android.widget.TextView; import android.widget.Toast; public class ActivityTest extends Activity implements OnQueryTextListener { private static final String COLUMN_ID = "_id"; private static final String COLUMN_TERM = "term"; private static final String DEFAULT = "default"; private SearchManager searchManager; private SearchView searchView; private MenuItem searchMenuItem; private SuggestAdapter suggestionsAdapter; private final ArrayList<String> suggestionsArray = new ArrayList<String>(); private final ArrayList<String> dummyArray = new ArrayList<String>(); @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create some dummy entries dummyArray.add("apples"); dummyArray.add("oranges"); dummyArray.add("bananas"); dummyArray.add("pears"); dummyArray.add("plums"); } @Override public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.main, menu); searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); searchMenuItem = menu.findItem(R.id.action_search); searchView = (SearchView) searchMenuItem.getActionView(); searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); searchView.setOnQueryTextListener(this); final MatrixCursor matrixCursor = getCursor(suggestionsArray); suggestionsAdapter = new SuggestAdapter(this, matrixCursor, suggestionsArray); searchView.setSuggestionsAdapter(suggestionsAdapter); suggestionsAdapter.notifyDataSetChanged(); return true; } @Override public boolean onQueryTextChange(final String newText) { suggestionsArray.clear(); for (int i = 0; i < dummyArray.size(); i++) { if (dummyArray.get(i).contains(newText)) { suggestionsArray.add(dummyArray.get(i)); } } final MatrixCursor matrixCursor = getCursor(suggestionsArray); suggestionsAdapter = new SuggestAdapter(this, matrixCursor, suggestionsArray); searchView.setSuggestionsAdapter(suggestionsAdapter); suggestionsAdapter.notifyDataSetChanged(); return true; } @Override public boolean onQueryTextSubmit(final String query) { // TODO Auto-generated method stub return false; } private class SuggestAdapter extends CursorAdapter implements OnClickListener { private final ArrayList<String> mObjects; private final LayoutInflater mInflater; private TextView tvSearchTerm; public SuggestAdapter(final Context ctx, final Cursor cursor, final ArrayList<String> mObjects) { super(ctx, cursor, 0); this.mObjects = mObjects; this.mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View newView(final Context ctx, final Cursor cursor, final ViewGroup parent) { final View view = mInflater.inflate(R.layout.list_item_search, parent, false); tvSearchTerm = (TextView) view.findViewById(R.id.tvSearchTerm); return view; } @Override public void bindView(final View view, final Context ctx, final Cursor cursor) { tvSearchTerm = (TextView) view.findViewById(R.id.tvSearchTerm); final int position = cursor.getPosition(); if (cursorInBounds(position)) { final String term = mObjects.get(position); tvSearchTerm.setText(term); view.setTag(position); view.setOnClickListener(this); } else { // Something went wrong } } private boolean cursorInBounds(final int position) { return position < mObjects.size(); } @Override public void onClick(final View view) { final int position = (Integer) view.getTag(); if (cursorInBounds(position)) { final String selected = mObjects.get(position); Toast.makeText(getApplicationContext(), selected, Toast.LENGTH_SHORT).show(); // Do something } else { // Something went wrong } } } private MatrixCursor getCursor(final ArrayList<String> suggestions) { final String[] columns = new String[] { COLUMN_ID, COLUMN_TERM }; final Object[] object = new Object[] { 0, DEFAULT }; final MatrixCursor matrixCursor = new MatrixCursor(columns); for (int i = 0; i < suggestions.size(); i++) { object[0] = i; object[1] = suggestions.get(i); matrixCursor.addRow(object); } return matrixCursor; } } 

En mi código actual, tengo una interfaz personalizada que rellena ArrayList con términos dinámicos extraídos de un servidor. Actualizar el conjunto de datos de esta manera:

 @Override public void onDataReceived(final ArrayList<String> results) { suggestionsArray.clear(); suggestionsArray.addAll(results); final MatrixCursor matrixCursor = getCursor(suggestionsArray); suggestionsAdapter = new SuggestAdapter(this, matrixCursor, suggestionsArray); searchView.setSuggestionsAdapter(suggestionsAdapter); suggestionsAdapter.notifyDataSetChanged(); } 

He encontrado que no inicializar un cursor vacío o volver a crear cada vez que causó problemas.

Espero eso ayude.

Hay un problema que observo en el enfoque anterior.

Cuando el usuario introduce un solo carácter (por ejemplo, "H" ), después de obtener las entradas de la base de datos y establecer el adaptador en searchView a través de searchView.setSuggestionsAdapter(<adapter>) , no se muestra la lista desplegable.

Sólo después de introducir un segundo carácter (por ejemplo, " ", "a" ), la lista de sugerencias se muestra. ¿Alguien está observando este comportamiento?

  • Inflación de un diseño xml en una clase de vista personalizada
  • ¿Cómo crear un semicírculo transparente?
  • Adición dinámica de vistas en un diseño de fragmento específico
  • Problema de visibilidad de Android con la casilla de verificación
  • Cómo configurar Tint en NavigationView a algunos iconos
  • Deslizar a otra vista en recyclerVer con ItemTouchHelper
  • Cómo configurar el color de fondo de una vista
  • Establecer funcionalidad del botón de retroceso del widget de búsqueda
  • Sube un diseño con el teclado suave pero guarda uno en la parte inferior
  • ¿Cómo puedo reconocer qué área de una imagen (no sólo las coordenadas) se ha tocado en Android?
  • Android superponer una vista ontop de todo?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.