it-swarm.com.de

notifyDataSetChanged funktioniert nicht mit dem benutzerdefinierten Adapter

Wenn ich meine ListView wieder auffüllen, rufe ich eine bestimmte Methode von meiner Adapter aus auf.

Problem :

Wenn ich updateReceiptsList von meiner Adapter aus anrufe, werden die Daten aktualisiert, aber meine ListView gibt die Änderung nicht wieder. 

Frage :

Warum zeigt meine ListView die neuen Daten nicht an, wenn ich notifyDataSetChanged anrufe?

Adapter :

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;
    }

}

--BEARBEITEN:

gefundene Problemumgehung

Nur um etwas Funktionscode zu haben, den ich jetzt mache:

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

Funktioniert, aber nicht so, wie es funktionieren soll.

93
Jasper

Ändern Sie Ihre Methode von 

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

Zu

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

Sie behalten also das gleiche Objekt wie Ihr DataSet in Ihrem Adapter.

278
tolgap

Ich habe das gleiche Problem und das ist mir klar. Wenn wir einen Adapter erstellen und auf listview setzen, zeigt listview auf ein Objekt im Speicher des Adapters, und die Daten in diesem Objekt werden in der Listview angezeigt.

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

wenn wir ein Objekt für den Adapter erneut mit anderen Daten erstellen und notifydatasetchanged ():

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

dies wirkt sich nicht auf Daten in der Listenansicht aus, da die Liste auf ein anderes Objekt verweist, dieses Objekt nichts über das neue Objekt im Adapter kennt und notifyDataSetChanged () nichts beeinflusst. Daher sollten wir die Daten im Objekt ändern und dies vermeiden Erstellen Sie erneut ein neues Objekt für den Adapter

22
Nhan Tran

Da ich bereits die Gründe für dieses Problem erklärt habe und auch, wie man es in einem anderen Antwort-Thread Here behandelt. Trotzdem teile ich die Lösungszusammenfassung hier.

Einer der Hauptgründe, warum notifyDataSetChanged() für Sie nicht funktioniert - ist 

Ihr Adapter verliert den Verweis auf Ihre Liste

Beim Erstellen und Hinzufügen einer neuen Liste zu Adapter. Befolgen Sie immer diese Richtlinien: 

  1. Initialisieren Sie arrayList, während Sie es global deklarieren.
  2. Fügen Sie dem Adapter die Liste direkt hinzu, ohne nach null und leeren Werten zu suchen Setzen Sie den Adapter direkt auf die Liste (prüfen Sie nicht auf Bedingung). Der Adapter garantiert Ihnen, dass, wo immer Sie Änderungen an den Daten des arrayList vornehmen, sich dies darum kümmert, aber die Referenz niemals verloren geht.
  3. Ändern Sie immer die Daten in der arrayList selbst (wenn Ihre Daten völlig neu sind , Dann können Sie adapter.clear() und arrayList.clear() vor Tatsächlich Daten zur Liste hinzufügen), aber setzen Sie den Adapter nicht, dh If .__ Daten werden in arrayList als nur adapter.notifyDataSetChanged() aufgefüllt.

Hoffe das hilft.

11

Versuchen Sie vielleicht, Ihre ListView zu aktualisieren:

receiptsListView.invalidate().

EDIT: Ein anderer Gedanke kam mir in den Sinn. Versuchen Sie für den Datensatz, den Listenansichts-Cache zu deaktivieren:

<ListView
    ...
    Android:scrollingCache="false"
    Android:cacheColorHint="@Android:color/transparent"
    ... />
3
Rafal Gałka

Ich hatte das gleiche Problem mit ListAdapter

Ich lasse Android Studio Methoden für mich implementieren und das ist was ich habe:

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

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }
    ...
}

Das Problem ist, dass diese Methoden keine super-Implementierungen aufrufen, sodass notifyDataSetChange niemals aufgerufen wird.

Entfernen Sie diese Überschreibungen entweder manuell oder fügen Sie Superaufrufe hinzu, und es sollte wieder funktionieren.

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

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
    super.unregisterDataSetObserver(observer);
}
3
Davor Zlotrg

Wenn adapter auf AutoCompleteTextView eingestellt ist, funktioniert notifyDataSetChanged() nicht. 

Benötigen Sie dies, um den Adapter zu aktualisieren:

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

myAutoComplete.setAdapter(myAutoCompleteAdapter);

Siehe: http://Android-er.blogspot.in/2012/10/autocompletetextview-with-dynamic.html

1
Prabs
class StudentAdapter extends BaseAdapter {
    ArrayList<LichHocDTO> studentList;

    private void capNhatDuLieu(ArrayList<LichHocDTO> list){
        this.studentList.clear();
        this.studentList.addAll(list);
        this.notifyDataSetChanged();
    }
}

Du kannst es versuchen. Es funktioniert für mich

0

Diesen Code hinzufügen

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

Ich habe das gleiche Problem, aber ich habe es gerade beendet !!

du solltest wechseln zu

public class ReceiptListAdapter erweitert BaseAdapter {

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

public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
    context = mcontext;
    receiptlist = rl;
    receiptviewlist = new ArrayList<>();
    receiptviewlist.clear();
    for(int i = 0; i < receiptlist.size(); i++){
      ReceiptViewHolder receiptviewholder = new ReceiptViewHolder();
      receiptviewlist.add(receiptviewholder);
    }
    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 receiptviewholder = receiptviewlist.get(position);
        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;
}

}

0
林權章

Wenn Sie zufällig auf diesem Thread gelandet sind und sich fragen, warum adapter.invaidate() oder adapter.clear() Methoden in Ihrem Fall nicht vorhanden sind, dann vielleicht, weil Sie RecyclerView.Adapter anstelle von BaseAdapter verwenden wird vom Fragesteller dieser Frage verwendet. Wenn das Löschen von list oder arraylist Ihr Problem nicht behebt, kann es vorkommen, dass Sie zwei oder mehr Instanzen des adapter ausführen, zum Beispiel:

Hauptaktivität

...

adapter = new CustomAdapter(list);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);

...

und
SomeFragment

...

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

...

Wenn Sie im zweiten Fall eine Änderung in der Liste der aufgeblasenen Ansichten in der Recycler-Ansicht erwarten, geschieht dies nicht, da beim zweiten Mal eine neue Instanz von adapter erstellt wird, die nicht mit der Recycler-Ansicht verknüpft ist . Das Setzen von notifyDataSetChanged im zweiten Adapter wird den Inhalt der Recycer-Ansicht nicht ändern. Erstellen Sie dazu eine neue Instanz der Recycler-Ansicht in SomeFragment und hängen Sie sie an die neue Instanz des Adapters an.

SomeFragment

...

recyclerView = new RecyclerView();
adapter = new CustomAdapter();
recyclerView.setAdapter(adapter);

...

Ich empfehle jedoch nicht, mehrere Instanzen derselben Adapter- und Recycler-Ansicht zu erstellen.

0
neer17