web-dev-qa-db-fra.com

notifyDataSetChanged ne fonctionne pas à partir de l'adaptateur personnalisé

Lorsque je repeuple ma ListView, j'appelle une méthode spécifique à partir de ma Adapter.

Problème :

Lorsque j'appelle updateReceiptsList depuis ma Adapter, les données sont actualisées mais ma ListView ne reflète pas le changement. 

Question :

Pourquoi ma ListView n'affiche-t-elle pas les nouvelles données lorsque j'appelle notifyDataSetChanged?

Adaptateur :

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

}

--MODIFIER:

trouvé Contournement

Juste pour avoir un code fonctionnel, je le fais maintenant:

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

Fonctionne, mais pas comment cela est supposé fonctionner.

93
Jasper

Changer votre méthode de 

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

À

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

Vous conservez donc le même objet que votre DataSet dans votre adaptateur.

278
tolgap

J'ai le même problème et je le réalise. Lorsque nous créons un adaptateur et le définissons sur listview, listview pointera vers un objet quelque part en mémoire que l'adaptateur contient, les données de cet objet s'afficheront dans listview.

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

si nous créons à nouveau un objet pour adapter avec une autre donnée et notifydatasetchanged ():

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

cela n'affectera pas les données dans listview car la liste pointe vers un objet différent, cet objet ne sait rien du nouvel objet de l'adaptateur, et notifyDataSetChanged () n'affecte rien . Nous devrions donc modifier les données dans l'objet et éviter de recréer un nouvel objet pour adaptateur

22
Nhan Tran

Comme j'ai déjà expliqué les raisons de ce problème et aussi comment le gérer dans un fil de réponse différent Ici . Je partage toujours le résumé de la solution ici.

Une des principales raisons pour lesquelles notifyDataSetChanged() ne fonctionnera pas pour vous - est, 

Votre adaptateur perd la référence à votre liste

Lors de la création et de l'ajout d'une nouvelle liste à la variable Adapter. Suivez toujours ces directives: 

  1. Initialisez le arrayList en le déclarant globalement.
  2. Ajoutez la liste à l'adaptateur directement sans vérifier les valeurs null et vide Définissez l'adaptateur dans la liste directement (ne recherchez aucune condition ). Adapter vous garantit que, peu importe où vous apportez Des modifications aux données du arrayList, il s’en occupera, mais ne perdez jamais la référence
  3. Modifiez toujours les données dans la liste même (si vos données sont complètement nouvelles .__, vous pouvez appeler adapter.clear() et arrayList.clear() avant En ajoutant des données à la liste), mais ne définissez pas l'adaptateur, à savoir If les données sont renseignées dans la variable arrayList au lieu de adapter.notifyDataSetChanged()

J'espère que cela t'aides.

11

Essayez peut-être d’actualiser votre ListView:

receiptsListView.invalidate().

EDIT: Une autre pensée me vint à l’esprit. Pour mémoire, essayez de désactiver le cache de la vue liste:

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

J'ai eu le même problème en utilisant ListAdapter

J'ai laissé Android Studio mettre en œuvre des méthodes pour moi et voici ce que j'ai obtenu:

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

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }
    ...
}

Le problème est que ces méthodes n'appellent pas les implémentations super, donc notifyDataSetChange n'est jamais appelé.

Supprimez ces substitutions manuellement ou ajoutez des super appels et cela devrait fonctionner à nouveau.

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

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

Si adapter est défini sur AutoCompleteTextView, alors notifyDataSetChanged() ne fonctionne pas. 

Besoin de ceci pour mettre à jour l'adaptateur:

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

myAutoComplete.setAdapter(myAutoCompleteAdapter);

Voir: 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();
    }
}

Tu peux essayer. Ça marche pour moi

0
Dũng Phạm Tiến

Ajouter ce code

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

J'ai le même problème mais je viens de le finir !!

vous devriez changer pour

classe publique ReceiptListAdapter extend 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
林權章

Si par hasard vous avez atterri sur ce fil et vous vous demandez pourquoi les méthodes adapter.invaidate() ou adapter.clear() ne sont pas présentes dans votre cas, c'est peut-être parce que vous utilisez peut-être RecyclerView.Adapter au lieu de BaseAdapter est utilisé par le demandeur de cette question. Si vous effacez la list ou arraylist sans résoudre votre problème, il peut arriver que vous vous fassiez deux fois ou plus de la adapter par exemple:

MainActivity

...

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

...

et
SomeFragment

...

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

...

Si dans le second cas, vous attendez un changement dans la liste des vues gonflées dans la vue recycleur, cela ne se produira pas, car, dans la deuxième fois, une nouvelle instance de la variable adapter ne sera pas attachée à la vue recycleur. . Le réglage de notifyDataSetChanged dans le deuxième adaptateur ne modifiera pas le contenu de la vue du recycleur. Pour cela, créez une nouvelle instance de la vue du recycleur dans SomeFragment et attachez-la à la nouvelle instance de l'adaptateur.

SomeFragment

...

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

...

Bien que, je ne recommande pas de créer plusieurs instances du même adaptateur et de la même vue Recycler.

0
neer17