2013-03-14 14 views
74

Quando ripopolare il mio ListView, chiamo un metodo specifico dal mio Adapter.notifyDataSetChange non funziona dall'adattatore personalizzato

Problema:

Quando chiamo updateReceiptsList dal mio Adapter, i dati vengono aggiornati, ma la mia ListView non riflette il cambiamento.

Domanda:

Perché lo ListView mostrano i nuovi dati quando chiamo notifyDataSetChanged?

adattatore:

public class ReceiptListAdapter extends BaseAdapter { 

    public List<Receipt> receiptlist; 
    private Context context; 
    private LayoutInflater inflater; 
    private DateHelpers dateH; 

    public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) { 
     context = mcontext; 
     receiptlist = rl; 
     Collections.reverse(receiptlist); 
     inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     dateH = new DateHelpers(); 
    } 

    @Override 
    public int getCount() { 
     try { 
      int size = receiptlist.size(); 
      return size; 
     } catch(NullPointerException ex) { 
      return 0; 
     } 
    } 

    public void updateReceiptsList(List<Receipt> newlist) { 
     receiptlist = newlist; 
     this.notifyDataSetChanged(); 
    } 

    @Override 
    public Receipt getItem(int i) { 
     return receiptlist.get(i); 
    } 

    @Override 
    public long getItemId(int i) { 
     return receiptlist.get(i).getReceiptId() ; 
    } 

    private String getPuntenString(Receipt r) { 
     if(r.getPoints().equals("1")) { 
      return "1 punt"; 
     } 
     return r.getPoints()+" punten"; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View vi=convertView; 

     final Receipt receipt = receiptlist.get(position); 
     ReceiptViewHolder receiptviewholder; 
     Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");   
     Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf"); 

     if (vi == null) { //convertview==null 
      receiptviewholder = new ReceiptViewHolder(); 
      vi = inflater.inflate(R.layout.view_listitem_receipt, null); 
      vi.setOnClickListener(null); 
      vi.setOnLongClickListener(null); 
      vi.setLongClickable(false); 
      receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop); 
      receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date); 
      receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price); 
      receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points); 
      receiptviewholder.shop.setTypeface(tf_hn_bold); 
      receiptviewholder.price.setTypeface(tf_hn_bold); 
      vi.setTag(receiptviewholder); 
     }else{//convertview is not null 
      receiptviewholder = (ReceiptViewHolder)vi.getTag(); 
     } 

     receiptviewholder.shop.setText(receipt.getShop()); 
     receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate()))); 
     receiptviewholder.price.setText("€ "+receipt.getPrice()); 
     receiptviewholder.points.setText(getPuntenString(receipt)); 

     vi.setClickable(false); 
     return vi; 
    } 

    public static class ReceiptViewHolder { 
     public TextView shop; 
     public TextView date; 
     public TextView price; 
     public TextView points; 
    } 

    public Object getFilter() { 
     // XXX Auto-generated method stub 
     return null; 
    } 

} 

--edit:

trovato Soluzione

solo per avere un po 'di codice funzionale che faccio ora:

listview.setAdapter(new ReceiptListAdapter(activity,mcontext, -new dataset-); 

Works, ma n come dovrebbe funzionare.

+0

http://stackoverflow.com/a/4198569/2382964, Hi Jasper consultare questo link ... questo vi aiuterà . –

risposta

227

cambiare il metodo da

public void updateReceiptsList(List<Receipt> newlist) { 
    receiptlist = newlist; 
    this.notifyDataSetChanged(); 
} 

Per

public void updateReceiptsList(List<Receipt> newlist) { 
    receiptlist.clear(); 
    receiptlist.addAll(newlist); 
    this.notifyDataSetChanged(); 
} 

in modo da mantenere lo stesso oggetto DataSet l'adattatore .

+0

considera di avere un oggetto padre come "ReceiptListObject" invece di un 'Elenco' di oggetti, cosa puoi fare per risolvere questo problema? – prom85

+0

@ prom85 può ArrayAdapters legarsi anche ad Oggetti diversi da Liste o da Array? Non lo sapevo. – tolgap

+0

si tratta di un 'BaseAdapter' e questo adattatore non sa a quali dati è associato ... quindi se ho un oggetto personalizzato e uso le funzioni personalizzate di questo oggetto (come' custObject.getCount() 'e' custObject.getChildAt (int i) 'per esempio), e voglio scambiare questo oggetto,' notifyDataSetChanged' non funziona ... comunque, penso che questo problema non si verifichi mai con un 'ArrayAdapter' – prom85

3

Forse ricarica la ListView:

receiptsListView.invalidate().

EDIT: Un altro pensiero mi è venuto in mente. Solo per la cronaca, provare a disattivare visualizzazione elenco di cache:

<ListView 
    ... 
    android:scrollingCache="false" 
    android:cacheColorHint="@android:color/transparent" 
    ... /> 
+1

provato, non funziona ancora ... – Jasper

+0

Stranamente, la mia ultima idea è di riassegnare l'adattatore alla vista elenco dopo la modifica dei dati. Ma suppongo che tu abbia già provato anche questo. –

16

Ho lo stesso problema e me ne rendo conto. Quando creiamo la scheda e la impostiamo in listview, listview punterà ad oggetti da qualche parte in memoria quale adattatore regge, i dati in questo oggetto verranno mostrati in listview.

adapter = new CustomAdapter(data); 
listview.setadapter(adapter); 

se creiamo un oggetto per l'adattatore con un altro dato di nuovo e notifydatasetchanged():

adapter = new CustomAdapter(anotherdata); 
adapter.notifyDataSetChanged(); 

questo non influenzerà i dati nel ListView perché l'elenco è rivolto a oggetto diverso, questo oggetto non sa nulla del nuovo oggetto nell'adattatore e notifyDataSetChanged() non influenza nulla. quindi dovremmo modificare i dati in oggetto e di evitare di creare un nuovo oggetto di nuovo per l'adattatore

+1

Questa è un'ottima risposta e spiegazione. –

+0

si sta ricreando l'oggetto adattatore, non è efficiente –

3

Ho avuto lo stesso problema utilizzando ListAdapter

lascio Android Studio implementare metodi per me e questo è quello che ho ottenuto:

public class CustomAdapter implements ListAdapter { 
    ... 
    @Override 
    public void registerDataSetObserver(DataSetObserver observer) { 

    } 

    @Override 
    public void unregisterDataSetObserver(DataSetObserver observer) { 

    } 
    ... 
} 

Il problema è che questi metodi non chiamano le implementazioni super in modo che notifyDataSetChange non venga mai chiamato.

Rimuovere manualmente queste sostituzioni o aggiungere chiamate super e dovrebbe funzionare di nuovo.

@Override 
public void registerDataSetObserver(DataSetObserver observer) { 
    super.registerDataSetObserver(observer); 
} 

@Override 
public void unregisterDataSetObserver(DataSetObserver observer) { 
    super.unregisterDataSetObserver(observer); 
} 
+0

Sapevo che questa era la risposta che stavo cercando non appena ho visto questo, un bell'aspetto esulta – Clocker

6

come ho già spiegato le ragioni alla base di questo problema e anche il modo di gestire la cosa in un diverso filo risposta Here. Comunque sto condividendo il sommario della soluzione qui.

Uno dei motivi principali notifyDataSetChanged() non funziona per voi - è,

L'adattatore perde riferimento alla tua lista.

Quando si crea e si aggiunge un nuovo elenco allo Adapter. Seguire sempre queste linee guida:

  1. Inizializzare il arrayList dichiarandolo globalmente.
  2. Aggiungere l'elenco direttamente all'adattatore senza controllo per valori nulli e vuoti . Impostare direttamente la scheda sulla lista (non verificare le condizioni di ). L'adattatore ti garantisce che, ovunque vengano apportate modifiche ai dati dello arrayList, si prenderà cura di esso, ma non si perderà mai il riferimento .
  3. modificare sempre i dati nella arrayList stesso (se i dati sono completamente nuovo di quanto è possibile chiamare adapter.clear() e arrayList.clear() prima in realtà l'aggiunta di dati alla lista), ma non impostare l'adattatore cioè se i nuovi dati è popolata nel arrayList non solo adapter.notifyDataSetChanged()

Spero che questo aiuti.

+1

Grazie! Il suggerimento al n. 2 ha aiutato. – Cheruby

0

aggiungere questo codice

runOnUiThread(new Runnable() { public void run() { 
       adapter = new CustomAdapter(anotherdata); 
      adapter.notifyDataSetChanged(); 
      } 
     }); 
0

Se adapter è impostato su AutoCompleteTextView poi notifyDataSetChanged() non funziona.

bisogno di questo per aggiornare l'adattatore:

myAutoCompleteAdapter = new ArrayAdapter<String>(MainActivity.this, 
     android.R.layout.simple_dropdown_item_1line, myList); 

myAutoComplete.setAdapter(myAutoCompleteAdapter); 

riferimento: http://android-er.blogspot.in/2012/10/autocompletetextview-with-dynamic.html

Problemi correlati