web-dev-qa-db-fra.com

Android: comment actualiser le contenu de ListView?

Ma ListView utilise une extension de BaseAdapter, je ne parviens pas à l'actualiser correctement. Lors de l'actualisation, il semble que les anciennes données soient superposées aux nouvelles données, jusqu'à ce qu'un événement de défilement se produise. Les anciennes lignes se superposent aux nouvelles lignes, mais les anciennes disparaissent lorsque je commence à faire défiler. 

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

private void updateData()
{
   List<DataItems> 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();
}
38
ab11

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

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

J'ai tout d'abord effacé les données de l'adaptateur, puis ajouté la nouvelle collection d'éléments et ensuite 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.

59
LoneDuck

Si je comprends bien, si vous souhaitez actualiser ListView immédiatement lorsque les données ont été modifiées, vous devez appeler notifyDataSetChanged() dans RunOnUiThread().

private void updateData() {
    List<Data> newData = getYourNewData();
    mAdapter.setList(yourNewList);

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
                mAdapter.notifyDataSetChanged();
        }
    });
}
12
khcpietro

Il n'est pas nécessaire de créer un nouvel adaptateur pour mettre à jour le contenu de votre ListView. Enregistrez 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 à cela:

private YourAdapter mAdapter;

protected void onCreate(...) {

    ...

    mAdapter = new YourAdapter(this);
    setListAdapter(mAdapter);

    updateData();
}

private void updateData() {
    List<Data> newData = getYourNewData();
    mAdapter.setList(yourNewList);
    mAdapter.notifyDataSetChanged();
}
11
Gubbel

Je pense que recharger le même adaptateur avec des données différentes serait plus ou mieux une technique . Mettez cette méthode dans votre classe Adapter avec le bon argument (la liste de données que vous voulez afficher comme noms dans mon cas) Appelez ceci où u mettre à jour les données de liste avec liste mise à jour (noms dans mon cas)

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

Si vous changez l'adaptateur ou si vous l'activez à plusieurs reprises lors de la mise à jour de la liste, une erreur de fermeture forcée entraînerait sûrement des problèmes à un moment donné. (Erreur: les données de liste ont été mises à jour mais l'adaptateur n'en informe pas la vue)

3
himb2001

J'ai moi aussi essayé invalidate (), invalidateViews (), notifyDataSetChanged (). Ils pourraient tous fonctionner dans des contextes particuliers mais cela n'a pas fonctionné dans mon cas.

Dans mon cas, j'ai dû ajouter 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, j'ai réalisé que les données étaient là mais pas restituées. Si invalidate () ou invalidateViews () ne rend pas (ce qui est supposé le faire), je ne sais pas ce qui le ferait.

Créer un nouvel objet 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 d'une nouvelle mémoire pour votre adaptateur, mais cela devrait être correct si le système Android est suffisamment intelligent et s'en occupe pour rester efficace.

Si vous retirez ceci de l'équation, le flux est presque identique à l'appel à notifyDataSetChanged. En un sens, le même ensemble de fonctions d’adaptateur est appelé dans les deux cas.

Donc, nous ne perdons pas beaucoup mais gagnons beaucoup.

3
Deepak G M

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

2
ingo

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

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

onCreate ():

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

onDataGet (après appel du service Web ou depuis une base de données locale ou autre):

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

BaseAdapter:

private class BuddyAdapter extends BaseAdapter { 

    private ArrayList<BuddyModel> mArrayList = new ArrayList<BuddyModel>();
    private LayoutInflater mLayoutInflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    private ViewHolder holder;

    public void setData(ArrayList<BuddyModel> 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;
    }
}

(À tout moment} _ vous voulez mettre à jour la vue liste appelez juste en dessous du code à deux lignes:

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

Terminé

1
Hiren Patel

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

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

Un autre moyen facile:

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