2010-03-01 15 views
11

Ho un ArrayAdapter (myAdapter) collegato a un componente AutoCompleteTextView (textView).
Una volta che l'utente preme un carattere, desidero popolare l'elenco a discesa di AutoCompleteTextView con gli elementi che contengono questo carattere.
Recupero gli elementi utilizzando AsyncTask (che utilizza un servizio Web).Android, funzione add() di ArrayAdapter non funzionante

Ho chiamato myAdapter.add (elemento) ma l'elenco a discesa è vuoto.
Ho aggiunto una chiamata myAdapter.getCount() dopo ogni aggiunta e mostra zero ogni volta. La chiamata a notifyDataSetChanged() non ha aiutato.
Ho persino provato ad aggiungere semplici oggetti String invece dei miei oggetti personalizzati, inutilmente.
Cosa sto sbagliando?

Modifica: Ho cambiato il codice come miette suggerito di seguito, ma ancora inutilmente.
Generalmente, quello che faccio è dopo che il testo è stato modificato nella mia vista testo completa automatica, chiamo un nuovo AsyncTask e gli passo il testo inserito e un gestore (vedi afterTextChanged()). L'attività recupera oggetti rilevanti per il testo e una volta fatto viene chiamato handleMessage() del gestore. In handleMessage() tento di popolare gli oggetti dell'adattatore. Ma ancora l'elenco a discesa dell'adattatore finisce vuoto.

Ecco il mio codice:

public class AddStockView extends Activity 
     implements OnClickListener, OnItemClickListener, TextWatcher { 

    ArrayAdapter<Stock> adapter; 
    AutoCompleteTextView textView; 
    Vector<Stock> stocks; 
    public AddStockView() { 
     // TODO Auto-generated constructor stub 
     stocks = new Vector<Stock>(); 
    } 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     setContentView(R.layout.add_stock_view); 

     findViewById(R.id.abort_button).setOnClickListener(this); 

     adapter = new ArrayAdapter<Stock>(this, 
     android.R.layout.simple_dropdown_item_1line, stocks); 
     //adapter.setNotifyOnChange(true); 
     textView = (AutoCompleteTextView) 
     findViewById(R.id.search_edit_text); 
     textView.setAdapter(adapter); 
     textView.setOnItemClickListener(this); 
     textView.addTextChangedListener(this); 

    } 
    @Override 
    public void onClick(View v) { 
     // TODO Auto-generated method stub 
     switch (v.getId()) 
     { 
     case R.id.abort_button: 
     finish(); 
     break; 
     case R.id.search_edit_text: 

     break; 
     } 
    } 
    @Override 
    public void onItemClick(AdapterView<?> parent, View v, 
          int position, long id) { 
     // TODO Auto-generated method stub 
     Stock stockToAdd = (Stock)parent.getAdapter().getItem(position); 
     //TODO: Add the above stock to user's stocks and close this screen 
     finish(); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     super.onCreateOptionsMenu(menu); 
     getMenuInflater().inflate(R.layout.menu, menu); 

     CategoryMenu.getInstance().populateMenu(menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     CategoryMenu.getInstance().menuItemSelected(item, this); 
     return false; 
    } 

    @Override 
    public boolean onPrepareOptionsMenu(Menu menu) { 
     return true; 
    } 
    @Override 
    public void afterTextChanged(Editable text) { 
     // TODO Auto-generated method stub 
     if (text.toString().equals("")) 
     return; 
     new AppTask().execute(new AppTask.Payload(Consts.taskType.SEARCH_STOCK, 
              new Object[] {text, handler}, this)); 

    } 
    @Override 
    public void beforeTextChanged(CharSequence a0, int a1, int a2, int a3) { 
     // TODO Auto-generated method stub 
    } 
    @Override 
    public void onTextChanged(CharSequence a0, int a1, int a2, int a3) { 
     // TODO Auto-generated method stub 
    } 
    private void addStockItemsToAdapter(Vector<Object> dataItems) 
    { 
     for (int i = 0; i <dataItems.size(); i++) 
     { 
     Stock stk = (Stock)dataItems.elementAt(i); 
     stocks.add(stk); 
     } 
    } 

    public void populateAdapter() 
    { 
     addStockItemsToAdapter(ContentReader.getInstance.getDataItems());  
     adapter.notifyDataSetChanged(); 
     int size = adapter.getCount(); // size == 0 STILL!!!! 
     textView.showDropDown(); 
    } 
    final Handler handler = new Handler() { 
     public void handleMessage(Message msg) { 
     populateAdapter(); 
     } 
    }; 
} 

Grazie mille, Rob

risposta

0

Dove si chiama addItemsToAdapter()? Puoi mostrarci come hai provato ad aggiungere semplici stringhe al tuo adattatore?

Edit: fuori dai commenti di codice utili:

adapter = new ArrayAdapter<Stock>(this, android.R.layout.simple_dropdown_item_1line, stocks); 
adapter.notifyDataSetChanged(); 
textView.setAdapter(adapter); 
+0

Ecco quello che ho fatto: ho definito un Handler e mettila nel mio AsyncTask (chiamato AppTask) params in questo modo: new AppTask().execute(new AppTask.Payload(Consts.taskType.SEARCH_STOCK, \t \t \t \t new Object[] {text, handler}, this)); Poi, in handleMessage di mia Handler() ho chiamato addItemsToAdapter . Per quanto riguarda le corde, ho dichiarato questa matrice: private static final String [] PAESI = new String [] { "Belgio", "Francia", "Italia", "Germania", "Spain" }; e invece di chiamare: myAdapter.add (tmpItem); Ho chiamato; myAdapter.add (COUNTRIES [i]) e persino COUNTRIES [0]. Grazie per il vostro aiuto! – Rob

+0

C'è un modo per pubblicare l'intero codice? – Rob

+0

Puoi caricare da qualche parte un progetto minimalista o modificare la tua domanda e aggiungere il codice ... – WarrenFaith

2

Creare un adattatore array con un vettore o una matrice simile:

ArrayAdapter(Context context, int textViewResourceId, T[] objects) 

Con l'inizializzazione vostra arrayadapter, si farà ascoltare all'array di oggetti. Non aggiungere elementi all'adattatore o svuotare l'adattatore, effettuare le aggiunte nell'array "objects" e cancellarlo. Dopo modifiche su questo array chiamare

adapter.notifyDataSetChanged(); 

Più specificamente

ArrayAdapter<YourContentType> yourAdapter = new ArrayAdapter<YourContentType> (this,R.id.OneOfYourTextViews,YourDataList); 

yourAdapter.notifyDataSetChanged();  
aTextView.setText(yourAdapter.isEmpty() ? "List is empty" : "I have too many objects:)"); 

Questo dovrebbe essere fatto dopo il caricamento YourDataList, ho controllato il codice, sei sicura conduttore richiama addStockItemsToAdapter() prima di guardare la scheda è vuota o non ? Dovresti anche controllare se il vettore di stock contiene elementi.

+0

Ho fatto come hai suggerito ma ancora non funziona. Ho un gestore il cui handleMessage() viene chiamato una volta arrivata la struttura dati. In handleMessage() chiamo una funzione che itera attraverso la struttura dei dati e aggiunge elementi agli oggetti T [] dell'adattatore e quindi chiama adapter.notifyDataSetChanged(). Dopo tutto questo adapter.getCount() restituisce ancora zero. Che diavolo potrebbe essere? – Rob

+0

Ciao di nuovo, sto cambiando la mia risposta per te. Ho provato quello che vuoi fare e funziona per me. – miette

+0

Ciao miette, mi fa piacere che tu guardi questo. Stai suggerendo lo stesso di Warren e in effetti questo ha risolto il problema. A proposito, mi rendo conto che chiamare notifyDataSetChanged() è ridondante poiché la "nuova istruzione ArrayAdapter" contiene l'origine dati aggiornata. Ho pensato che avrei potuto avere la mia origine dati (YourDataList) vuota al momento della creazione dell'adattatore, aggiungere elementi lungo il percorso e chiamare notifyDataSetChanged() una volta terminata l'aggiunta, ma sembra che non funzioni, vero? Ad ogni modo, ho molto obbligato il mio uomo. – Rob

12

Ho avuto lo stesso identico problema. Dopo aver esaminato il codice sorgente ArrayAdapter e AutoCompleteTextView, ho scoperto che il problema era, insomma, che:

  • la lista oggetto originale viene memorizzato in ArrayAdapter.mObjects.
  • Tuttavia, AutoCompleteTextView attiva il filtro ArrayAdapter, ovvero i nuovi oggetti aggiunti a ArrayAdapter.mOriginalValues, mentre mObjects contiene gli oggetti filtrati.
  • ArrayAdapter.getCount() restituisce sempre la dimensione di mObjects.

La mia soluzione era di ignorare ArrayAdapter.getFilter() per restituire un filtro non filtrante. In questo modo, è null e mObjects in tutti i casi.

codice di esempio:

public class MyAdapter extends ArrayAdapter<String> { 
    NoFilter noFilter; 
    /* 
    ... 
    */ 

    /** 
    * Override ArrayAdapter.getFilter() to return our own filtering. 
    */ 
    public Filter getFilter() { 
     if (noFilter == null) { 
      noFilter = new NoFilter(); 
     } 
     return noFilter; 
    } 

    /** 
    * Class which does not perform any filtering. 
    * Filtering is already done by the web service when asking for the list, 
    * so there is no need to do any more as well. 
    * This way, ArrayAdapter.mOriginalValues is not used when calling e.g. 
    * ArrayAdapter.add(), but instead ArrayAdapter.mObjects is updated directly 
    * and methods like getCount() return the expected result. 
    */ 
    private class NoFilter extends Filter { 
     protected FilterResults performFiltering(CharSequence prefix) { 
      return new FilterResults(); 
     } 

     protected void publishResults(CharSequence constraint, 
             FilterResults results) { 
      // Do nothing 
     } 
    } 
} 
+0

SEI MERAVIGLIOSO !!! – Anderson

+0

in altri casi il filtro è ciò di cui hai realmente bisogno e puoi utilizzarlo come spiegato [qui] (http://android.foxykeep.com/dev/how-to-add-autocompletion-to-an-edittext) nel Esempio di servizio Web. – vfede

Problemi correlati