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.
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.
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
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:
arrayList
en le déclarant globalement.arrayList
, il s’en occupera, mais ne perdez jamais la référence 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.
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"
... />
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);
}
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
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
Ajouter ce code
runOnUiThread(new Runnable() { public void run() {
adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();
}
});
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;
}
}
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.