Android: comment actualiser le contenu de ListView?

Mon ListView utilise une extension de BaseAdapter , je ne parviens pas à l’actualiser correctement. Lorsque je rafraîchit, il apparaît que les anciennes données s’ajoutent aux nouvelles données jusqu’à ce qu’un événement de défilement se produise. Les anciennes lignes sont dessinées par-dessus les nouvelles lignes, mais les anciennes lignes disparaissent lorsque je lance le défilement.

J’ai essayé d’appeler invalidateViews() , notifyDataSetChanged() et notifyDataSetInvalidated() . Mon code ressemble à quelque chose comme:

 private void updateData() { List newList = getNewList(); MyAdapter adapter = new MyAdapter(getContext()); //my adapter holds an internal list of DataItems adapter.setList(newList); mList.setAdapter(adapter); adapter.notifyDataSetChanged(); mList.invalidateViews(); } 

Pour ceux qui ont encore des problèmes, je l’ai résolu de cette façon:

 List newItems = databaseHandler.getItems(); ListArrayAdapter.clear(); ListArrayAdapter.addAll(newItems); ListArrayAdapter.notifyDataSetChanged(); databaseHandler.close(); 

J’ai d’abord effacé les données de l’adaptateur, puis ajouté la nouvelle collection d’éléments, puis seulement défini notifyDataSetChanged(); Ce n’était pas clair pour moi au début, alors je voulais le signaler. Notez que sans appeler notifyDataSetChanged() la vue ne sera pas mise à jour.

À ma connaissance, si vous souhaitez actualiser ListView immédiatement lorsque les données ont changé, vous devez appeler notifyDataSetChanged() dans RunOnUiThread() .

 private void updateData() { List newData = getYourNewData(); mAdapter.setList(yourNewList); runOnUiThread(new Runnable() { @Override public void run() { mAdapter.notifyDataSetChanged(); } }); } 

Vous n’avez pas besoin de créer un nouvel adaptateur pour mettre à jour le contenu de votre ListView. Stockez simplement votre adaptateur dans un champ et mettez à jour votre liste avec le code suivant:

 mAdapter.setList(yourNewList); mAdapter.notifyDataSetChanged(); 

Pour clarifier cela, votre activité devrait ressembler à ceci:

 private YourAdapter mAdapter; protected void onCreate(...) { ... mAdapter = new YourAdapter(this); setListAdapter(mAdapter); updateData(); } private void updateData() { List newData = getYourNewData(); mAdapter.setList(yourNewList); mAdapter.notifyDataSetChanged(); } 

J’ai aussi essayé d’invalider (), invalidateViews (), notifyDataSetChanged (). Ils pourraient tous travailler dans certains contextes particuliers, mais ils n’ont pas fait le travail dans mon cas.

Dans mon cas, j’ai dû append de nouvelles lignes à la liste et cela ne fonctionne tout simplement pas. La création d’un nouvel adaptateur a résolu le problème.

Lors du débogage, je me suis rendu compte que les données étaient là, mais simplement pas rendues. Si invalidate () ou invalidateViews () ne rend pas (ce qu’il est censé), je ne sais pas ce qui le ferait.

Créer un nouvel object Adaptateur pour actualiser les données modifiées ne semble pas être une mauvaise idée. Cela fonctionne vraiment. Le seul inconvénient pourrait être le temps consacré à l’allocation de nouvelles mémoires pour votre adaptateur, mais cela devrait être correct en supposant que le système Android est suffisamment intelligent et en prend soin pour le garder efficace.

Si vous retirez cela de l’équation, le stream est presque le même que pour appeler notifyDataSetChanged. Dans le sens, le même ensemble de fonctions d’adaptateur est appelé dans les deux cas.

Donc, nous ne perdons pas beaucoup mais gagnons beaucoup.

Je pense que remplir le même adaptateur avec des données différentes serait une technique plus ou moins efficace. Mettez cette méthode dans votre classe Adapter avec l’argument correct (la liste de données que vous souhaitez afficher en tant que noms dans mon cas) Appelez ceci où vous mettez à jour les données de la liste avec la liste mise à jour (noms dans mon cas)

 public void refill(ArrayList names) { list.clear(); list.addAll(names); list.notifyDataSetChanged(); } 

Si vous modifiez la carte ou définissez la carte encore et encore lorsque la liste est mise à jour, une erreur de fermeture forcée entraînera certainement des problèmes à un moment donné. (Erreur: les données de la liste ont été mises à jour mais l’adaptateur n’a pas signalé l’affichage de la liste)

Je fais la même chose en utilisant invalidateViews () et cela fonctionne pour moi. Si vous voulez l’invalider immédiatement, vous pouvez essayer d’appeler postInvalidate après avoir appelé invalidateViews.

Mettre à jour le contenu de ListView par le code ci-dessous:

 private ListView listViewBuddy; private BuddyAdapter mBuddyAdapter; private ArrayList buddyList = new ArrayList(); 

onCreate () :

 listViewBuddy = (ListView)findViewById(R.id.listViewBuddy); mBuddyAdapter = new BuddyAdapter(); listViewBuddy.setAdapter(mBuddyAdapter); 

onDataGet (après l’appel du service Web ou de la firebase database locale ou autre):

 mBuddyAdapter.setData(buddyList); mBuddyAdapter.notifyDataSetChanged(); 

BaseAdapter :

 private class BuddyAdapter extends BaseAdapter { private ArrayList mArrayList = new ArrayList(); private LayoutInflater mLayoutInflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); private ViewHolder holder; public void setData(ArrayList list){ mArrayList = list; } @Override public int getCount() { return mArrayList.size(); } @Override public BuddyModel getItem(int position) { return mArrayList.get(position); } @Override public long getItemId(int pos) { return pos; } private class ViewHolder { private TextView txtBuddyName, txtBuddyBadge; } @SuppressLint("InflateParams") @Override public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { holder = new ViewHolder(); convertView = mLayoutInflater.inflate(R.layout.row_buddy, null); // bind views holder.txtBuddyName = (TextView) convertView.findViewById(R.id.txtBuddyName); holder.txtBuddyBadge = (TextView) convertView.findViewById(R.id.txtBuddyBadge); // set tag convertView.setTag(holder); } else { // get tag holder = (ViewHolder) convertView.getTag(); } holder.txtBuddyName.setText(mArrayList.get(position).getFriendId()); int badge = mArrayList.get(position).getCount(); if(badge!=0){ holder.txtBuddyBadge.setVisibility(View.VISIBLE); holder.txtBuddyBadge.setText(""+badge); }else{ holder.txtBuddyBadge.setVisibility(View.GONE); } return convertView; } } 

Lorsque vous souhaitez mettre à jour Listview, appelez simplement le code ci-dessous:

  mBuddyAdapter.setData(Your_Updated_ArrayList); mBuddyAdapter.notifyDataSetChanged(); 

Terminé

Seulement cela fonctionne pour moi à chaque fois, notez que je ne sais pas si cela cause d’autres complications ou problèmes de performance:

 private void updateListView(){ listview.setAdapter(adapter); } 

Un autre moyen facile:

 //In your ListViewActivity: public void refreshListView() { listAdapter = new ListAdapter(this); setListAdapter(listAdapter); }