2012-07-23 5 views
9

He creado una actividad de búsqueda. Ahora, quiero agregar sugerencias de búsqueda que se toman del servicio web. Quiero obtener esas sugerencias de forma asincrónica. De acuerdo con Adding Custom Suggestions, tengo que anular el método de consulta, hacer mi búsqueda de sugerencias, crear mi propio MatrixCursor y devolverlo. pero este es el problema, mi solicitud para obtener la sugerencia es asincrónica. por lo tanto, cuando el resultado vuelve de la red fuera del alcance del método de consulta.Android: ¿Cómo obtener sugerencias de búsqueda de manera asincrónica desde la web?

+0

de búsqueda sugerencia que decir AutoCompleteTextView ?? –

+1

No. Estoy usando el cuadro de diálogo de búsqueda de Android. como se describe en la documentación: "Al usar el cuadro de diálogo de búsqueda de Android o el widget de búsqueda, puede proporcionar sugerencias de búsqueda personalizadas que se crean a partir de datos en su aplicación". Lo que intento hacer es obtener esa sugerencia del servidor y no de DB. – toko

Respuesta

0

Lo más parecido que he encontrado para solucionar esto, es mediante el uso de un ContentProvider y hacer la solicitud de red en el método de su proveedor (aun cuando esto va en contra de las mejores prácticas) Query, con el resultado de que puede crear un MatrixCursor como se muestra here y here.

Todavía estoy buscando otras opciones como usar un SyncAdapter, que parece abrumador con el único propósito de mostrar sugerencias que no se utilizan en ningún otro lado.

Otra opción que tomé para hacer esto de forma asincrónica es usar AutoCompleteTextView, de esta manera puedes crear un adaptador personalizado, donde puedes implementar la función getFilter como se muestra en this answer.

+0

Crear MatrixCursor como se muestra en los ejemplos, no resuelve el problema ya que quiero obtener las sugerencias de forma asincrónica del servidor. – toko

+0

@toko, por favor, mira mi edición de respuestas, agregué otra opción, esa es la que tomé al final, que no bloqueará tu subproceso de interfaz de usuario mientras obtengas los datos de la web. –

+0

el problema es que no estoy usando AutoCompleteTextView. Estoy usando el diálogo de la interfaz de búsqueda: http://developer.android.com/guide/topics/search/search-dialog.html – toko

1

Parece que la solicitud al proveedor de contenido de sugerencias no se ejecuta en el hilo de la interfaz de usuario, de todos modos, de acuerdo con esta respuesta: https://stackoverflow.com/a/12895381/621690. Si puede cambiar su solicitud http, puede simplemente llamarla bloqueo dentro del método de consulta. Podría ayudar a escuchar interrupciones u otras señales (tal vez personalizadas) para detener solicitudes innecesarias.

Otra opción: si no desea cambiar ninguna clase de solicitud que ya sea asincrónica (como si está utilizando Robospice), debería simplemente devolver la referencia de MatrixCursor y rellenarla más adelante. La clase AbstractCursor ya implementa el patrón Observer y envía notificaciones en caso de cambios. Si el sistema de búsqueda está escuchando, debe manejar cualquier cambio en los datos. Todavía tengo que implementarlo yo mismo, así que no puedo confirmar que funcionará tan bien como lo imagino. (Eche un vistazo a la fuente de CursorLoader para obtener más inspiración.)

Y, de todos modos, ¿no es ese el objetivo de un cursor? De lo contrario, simplemente podríamos devolver una lista con datos.

ACTUALIZACIÓN: Para mí, el uso de un MatrixCursor no funcionó. En su lugar, he implementado otras dos soluciones:

  1. Utilizando el AutoCompleteTextField en combinación con una subclase personalizada de ArrayAdapter que a su vez utiliza un subclase personalizada de filtro. El método Filter#performFiltering() (que anulo con la llamada síncrona al servicio remoto) se llama de manera asíncrona y el subproceso de la interfaz de usuario no está bloqueado.
  2. Uso del SearchWidget con SearchableActivity y un ArrayAdapter personalizado (sin filtro personalizado). Cuando la intención de búsqueda entra en juego, se inicia la solicitud remota (Robospice) y cuando se trata de vuelta a través de devolución de llamada, llamo al siguiente método personalizado en mi ArrayAdapter<Tag> subclase:

    public void addTags(List<Tag> items) { 
        if (items != null && items.size() > 0) { 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 
          super.setNotifyOnChange(false); 
          for (Tag tag : items) { 
           super.add(tag); 
          } 
          super.notifyDataSetChanged(); 
         } else { 
          super.addAll(items); 
         } 
        } 
    } 
    

Este método se encarga de desencadenar las notificaciones en el adaptador y, por lo tanto, la lista de resultados de búsqueda.

+0

Definitivamente la idea correcta. Intento hacer exactamente esto, pero parece que las sugerencias de búsqueda de Android no escuchan los cambios del cursor. :/Específicamente, estoy llamando a 'ContentResolver.notifyChange()', pero no veo que ['SuggestionAdapter'] de Android (https://android.googlesource.com/platform/frameworks/base/+/jb- release/core/java/android/widget/SuggestionsAdapter.java) llama a 'registerContentObserver()'. ¿Algunas ideas? ¿Me estoy perdiendo algo? – ryan

+0

Parecía la idea correcta, pero no funcionó (al menos no para mí). Actualicé mi respuesta con mis soluciones actuales. – Risadinha

+0

gracias por la actualización! esas soluciones actuales tienen sentido para los resultados de búsqueda. Todavía estoy buscando una forma de actualizar [search _suggestions_] (http://developer.android.com/guide/topics/search/adding-custom-suggestions.html) después de que hayan sido devueltos. sospecho que puede que no haya una manera ... pero si sabes una, ¡háznoslo saber! – ryan

0

Aquí es un ejemplo de SearchView con sugerencias procedentes de un servicio de red (utilicé reequipamiento):

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.menu_search_activity, menu); 

     final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.search)); 

     final CursorAdapter suggestionAdapter = new SimpleCursorAdapter(this, 
       android.R.layout.simple_list_item_1, 
       null, 
       new String[]{SearchManager.SUGGEST_COLUMN_TEXT_1}, 
       new int[]{android.R.id.text1}, 
       0); 
     final List<String> suggestions = new ArrayList<>(); 

     searchView.setSuggestionsAdapter(suggestionAdapter); 
     searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { 
      @Override 
      public boolean onSuggestionSelect(int position) { 
       return false; 
      } 

      @Override 
      public boolean onSuggestionClick(int position) { 
       searchView.setQuery(suggestions.get(position), false); 
       searchView.clearFocus(); 
       doSearch(suggestions.get(position)); 
       return true; 
      } 
     }); 

     searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 

      @Override 
      public boolean onQueryTextSubmit(String query) { 
       return false; 
      } 

      @Override 
      public boolean onQueryTextChange(String newText) { 

       MyApp.autocompleteService.search(newText, new Callback<Autocomplete>() { 
        @Override 
        public void success(Autocomplete autocomplete, Response response) { 
         suggestions.clear(); 
         suggestions.addAll(autocomplete.suggestions); 

         String[] columns = { 
           BaseColumns._ID, 
           SearchManager.SUGGEST_COLUMN_TEXT_1, 
           SearchManager.SUGGEST_COLUMN_INTENT_DATA 
         }; 

         MatrixCursor cursor = new MatrixCursor(columns); 

         for (int i = 0; i < autocomplete.suggestions.size(); i++) { 
          String[] tmp = {Integer.toString(i), autocomplete.suggestions.get(i), autocomplete.suggestions.get(i)}; 
          cursor.addRow(tmp); 
         } 
         suggestionAdapter.swapCursor(cursor); 
        } 

        @Override 
        public void failure(RetrofitError error) { 
         Toast.makeText(SearchFoodActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show(); 
         Log.w("autocompleteService", error.getMessage()); 
        } 
       }); 
       return false; 
      } 
     }); 

     return true; 
} 
+2

¿Puede explicar mejor su implementación? ¿Cómo funciona el método 'doSearch (suggestions.get (position))'? Gracias –

Cuestiones relacionadas