2011-02-16 19 views
71

Quiero usar un AutoCompleteTextView en mi actividad y llenar los datos como los tipos de usuario consultando una API web. ¿Cómo voy a hacer esto?¿Cómo uso AutoCompleteTextView y lo lleno con datos de una API web?

¿Creé una nueva clase y anulé AutoCompleteTextView.performFiltering, o utilizo un adaptador de lista personalizado y proporciono un android.widget.Filter personalizado que anula la realización de Filtrado?

¿O hay una manera mejor de obtener mi objetivo final?

He hecho algo similar, pero era para el cuadro de búsqueda rápida e implicaba la implementación de un servicio, pero creo que no es lo que quiero hacer aquí.

+4

un enlace excelente para futuros espectadores :): http: //makovkastar.github. io/blog/2014/04/12/android-autocompletetextview-with-suggestions-from-a-web-service/ – Tina

Respuesta

90

Se me ocurrió una solución, no sé si es la mejor solución, pero parece funcionar muy bien. Lo que hice fue crear un adaptador personalizado que amplía ArrayAdapter. En el adaptador personalizado anulé getFilter y creé mi propia clase de filtro que anula el filtro de ejecución. Esto inicia un nuevo hilo para que no interrumpa la IU. A continuación se muestra un ejemplo de barebones.

MyActivity.java

public class MyActivity extends Activity { 
    private AutoCompleteTextView style; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     ... 
     style = (AutoCompleteTextView) findViewById(R.id.style); 
     adapter = new AutoCompleteAdapter(this, android.R.layout.simple_dropdown_item_1line); 
     style.setAdapter(adapter); 
    } 
} 

AutoCompleteAdapter.java

public class AutoCompleteAdapter extends ArrayAdapter<Style> implements Filterable { 
    private ArrayList<Style> mData; 

    public AutoCompleteAdapter(Context context, int textViewResourceId) { 
     super(context, textViewResourceId); 
     mData = new ArrayList<Style>(); 
    } 

    @Override 
    public int getCount() { 
     return mData.size(); 
    } 

    @Override 
    public Style getItem(int index) { 
     return mData.get(index); 
    } 

    @Override 
    public Filter getFilter() { 
     Filter myFilter = new Filter() { 
      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       FilterResults filterResults = new FilterResults(); 
       if(constraint != null) { 
        // A class that queries a web API, parses the data and returns an ArrayList<Style> 
        StyleFetcher fetcher = new StyleFetcher(); 
        try { 
         mData = fetcher.retrieveResults(constraint.toString()); 
        } 
        catch(Exception e) { 
         Log.e("myException", e.getMessage()); 
        } 
        // Now assign the values and count to the FilterResults object 
        filterResults.values = mData; 
        filterResults.count = mData.size(); 
       } 
       return filterResults; 
      } 

      @Override 
      protected void publishResults(CharSequence contraint, FilterResults results) { 
       if(results != null && results.count > 0) { 
       notifyDataSetChanged(); 
       } 
       else { 
        notifyDataSetInvalidated(); 
       } 
      } 
     }; 
     return myFilter; 
    } 
} 
+2

Buena solución, exactamente lo que necesitaba. Sin embargo, si pudiera preguntar ... devuelve un estilo a su diseño simple_dropdown_item_1line. ¿Cómo recuperas un valor apropiado de tu clase de Estilo? Para mí, es una clase que he creado y quiero que el valor de texto getStyleName se muestre en mi elemento de la lista, pero simplemente muestra el nombre de la clase. – bugfixr

+6

@bugfixr Agregue un método público toString en su clase. En mi ejemplo fue: public String toString() {return name; } –

+0

Siempre obtengo nulo como variable de restricción. ¿Qué estoy haciendo mal? Estoy usando Honeycomb como dispositivo – Alex

3

Chu: Para personalizar el modo de vista se ve y obtener un mayor control sobre desenvolver el objeto, haga lo siguiente ...

@Override 
    public View getView (int position, View convertView, ViewGroup parent) { 
     TextView originalView = (TextView) super.getView(position, convertView, parent); // Get the original view 

     final LayoutInflater inflater = LayoutInflater.from(getContext()); 
     final TextView view = (TextView) inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false); 

     // Start tweaking 
     view.setText(originalView.getText()); 
     view.setTextColor(R.color.black); // also useful if you have a color scheme that makes the text show up white 
     view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); // override the text size 
     return view; 
    } 
5

Ampliando en AJ. la respuesta anterior, el siguiente adaptador personalizado incluye s el manejo de las peticiones al servidor y JSON análisis sintáctico, así:

class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable 
{ 
    private ArrayList<String> data; 
    private final String server = "http://myserver/script.php?query="; 

    AutoCompleteAdapter (@NonNull Context context, @LayoutRes int resource) 
    { 
     super (context, resource); 
     this.data = new ArrayList<>(); 
    } 

    @Override 
    public int getCount() 
    { 
     return data.size(); 
    } 

    @Nullable 
    @Override 
    public String getItem (int position) 
    { 
     return data.get (position); 
    } 

    @NonNull 
    @Override 
    public Filter getFilter() 
    { 
     return new Filter() 
     { 
      @Override 
      protected FilterResults performFiltering (CharSequence constraint) 
      { 
       FilterResults results = new FilterResults(); 
       if (constraint != null) 
       { 
        HttpURLConnection conn = null; 
        InputStream input = null; 
        try 
        { 
         URL url = new URL (server + constraint.toString()); 
         conn = (HttpURLConnection) url.openConnection(); 
         input = conn.getInputStream(); 
         InputStreamReader reader = new InputStreamReader (input, "UTF-8"); 
         BufferedReader buffer = new BufferedReader (reader, 8192); 
         StringBuilder builder = new StringBuilder(); 
         String line; 
         while ((line = buffer.readLine()) != null) 
         { 
          builder.append (line); 
         } 
         JSONArray terms = new JSONArray (builder.toString()); 
         ArrayList<String> suggestions = new ArrayList<>(); 
         for (int ind = 0; ind < terms.length(); ind++) 
         { 
          String term = terms.getString (ind); 
          suggestions.add (term); 
         } 
         results.values = suggestions; 
         results.count = suggestions.size(); 
         data = suggestions; 
        } 
        catch (Exception ex) 
        { 
         ex.printStackTrace(); 
        } 
        finally 
        { 
         if (input != null) 
         { 
          try 
          { 
           input.close(); 
          } 
          catch (Exception ex) 
          { 
           ex.printStackTrace(); 
          } 
         } 
         if (conn != null) conn.disconnect(); 
        } 
       } 
       return results; 
      } 

      @Override 
      protected void publishResults (CharSequence constraint, FilterResults results) 
      { 
       if (results != null && results.count > 0) 
       { 
        notifyDataSetChanged(); 
       } 
       else notifyDataSetInvalidated(); 
      } 
     }; 
    } 

y utilizarlo de la misma manera:

public class MyActivity extends Activity 
{ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     ... 
     AutoCompleteTextView textView = (AutoCompleteTextView) findViewById (R.id.style); 
     int layout = android.R.layout.simple_list_item_1; 
     AutoCompleteAdapter adapter = new AutoCompleteAdapter (this, layout); 
     textView.setAdapter (adapter); 
    } 
} 
Cuestiones relacionadas