78 votes

Rafraîchissement d'une seule rangée d'une liste Android

Une fois que j'ai obtenu les données d'une seule ligne d'une ListView Je veux mettre à jour cette seule ligne.

Actuellement, j'utilise notifyDataSetChanged(); mais cela rend le View réagissent très lentement. Existe-t-il d'autres solutions ?

90voto

GriffonRL Points 1361

En tant que Romain Guy a expliqué il y a quelque temps pendant le Session Google I/O La façon la plus efficace de mettre à jour une seule vue dans une vue de liste est quelque chose comme ce qui suit (cette mise à jour des données de la vue entière) :

ListView list = getListView();
int start = list.getFirstVisiblePosition();
for(int i=start, j=list.getLastVisiblePosition();i<=j;i++)
    if(target==list.getItemAtPosition(i)){
        View view = list.getChildAt(i-start);
        list.getAdapter().getView(i, view, list);
        break;
    }

En supposant que target est un élément de l'adaptateur.

Ce code récupère le ListView puis parcourez les vues actuellement affichées, comparez l'affichage de l target que vous recherchez avec chaque élément de vue affiché, et si votre cible se trouve parmi ceux-ci, récupérez la vue englobante et exécutez l'adaptateur getView sur cette vue pour rafraîchir l'affichage.

A titre d'information invalidate ne fonctionne pas comme certaines personnes l'espèrent et ne rafraîchit pas la vue comme le fait getView, notifyDataSetChanged reconstruira la liste entière et finira par appeler getview pour chaque élément affiché et invalidateViews affectera également un groupe.

Une dernière chose, on peut aussi obtenir des performances supplémentaires si on a besoin de changer seulement un enfant d'une vue de ligne et pas la ligne entière comme getView fait. Dans ce cas, le code suivant peut remplacer list.getAdapter().getView(i, view, list); (exemple pour modifier un TextView texte) :

((TextView)view.findViewById(R.id.myid)).setText("some new text");

In code we trust.

17 votes

Vous devriez probablement juste lier votre autre réponse stackoverflow.com/a/9987616/1026132 au lieu de copier et coller ici. Cela permettrait de réduire la quantité de contenu dupliqué dans SO.

2 votes

Comment mettre en œuvre ce système avec différents types de vues ?

1 votes

Le lien vers "Google I/O session" dans la réponse est mort.

30voto

Daniel Velkov Points 9244

Une option consiste à manipuler le ListView directement. Vérifiez d'abord si l'index de la ligne mise à jour se situe entre getFirstVisiblePosition() et getLastVisiblePosition() ces deux éléments vous donnent la première et la dernière position de l'adaptateur qui sont visibles à l'écran. Ensuite, vous pouvez obtenir la ligne View avec getChildAt(int index) et le changer.

3 votes

Merci. Cela fonctionnerait si je suis édition la disposition actuelle de l'enfant. Mais que se passe-t-il si je veux changer complètement la mise en page (en gonflant un autre xml) ? Si j'appelle newView(...) sur l'adaptateur, cela me donne une vue différente qui n'est cependant pas mise dans la listView .

1 votes

@hadi vous devriez jeter un coup d'oeil à cette réponse : stackoverflow.com/a/11568271/858626

29voto

John Starr Dewar Points 701

Cette méthode plus simple fonctionne bien pour moi, et il suffit de connaître l'indice de position pour avoir accès à la vue :

// mListView is an instance variable

private void updateItemAtPosition(int position) {
    int visiblePosition = mListView.getFirstVisiblePosition();
    View view = mListView.getChildAt(position - visiblePosition);
    mListView.getAdapter().getView(position, view, mListView);
}

2 votes

Fonctionne comme un charme, +1

0 votes

Je vais envoyer ces valeurs mises à jour à la vue détaillée d'une autre page si l'utilisateur fait des changements sur cette page de détails comment mettre à jour de nouveau à la liste s'il vous plaît.

6voto

SkolVikingsGuy Points 125

Le code suivant a fonctionné pour moi. Notez que lorsque vous appelez GetChild(), vous devez compenser par le premier élément de la liste puisque c'est relatif à celui-ci.

int iFirst = getFirstVisiblePosition();
int iLast = getLastVisiblePosition();

if ( indexToChange >= numberOfRowsInSection() ) {
    Log.i( "MyApp", "Invalid index. Row Count = " + numberOfRowsInSection() );
}
else {      
    if ( ( index >= iFirst ) && ( index <= iLast ) ) {
        // get the view at the position being updated - need to adjust index based on first in the list
        View vw = getChildAt( sysvar_index - iFirst );
        if ( null != vw ) {
            // get the text view for the view
            TextView tv = (TextView) vw.findViewById(com.android.myapp.R.id.scrollingListRowTextView );
            if ( tv != null ) {
                // update the text, invalidation seems to be automatic
                tv.setText( "Item = " + myAppGetItem( index ) + ". Index = " + index + ". First = " + iFirst + ". Last = " + iLast );
            }
        }
    }
}

0 votes

Dans cet exemple sysvar_index signifie la position de la ligne que vous voulez mettre à jour

2voto

vedant1811 Points 658

Il existe une autre solution beaucoup plus efficace, si elle correspond à votre cas d'utilisation.

Si vous changez l'état et pouvez d'une manière ou d'une autre appeler le bon (en connaissant la position) mListView.getAdapter().getView() il sera le plus efficace de tous.

Je peux démontrer une manière très simple de le faire, en créant une classe interne anonyme dans mon fichier ListAdapter.getView() la classe. Dans cet exemple, j'ai un TextView montrant un texte "nouveau" et cette vue est définie sur GONE lorsque l'on clique sur l'élément de la liste :

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // assign the view we are converting to a local variable
    View view = convertView;

    Object quotation = getItem(position);
    // first check to see if the view is null. if so, we have to inflate it.
    if (view == null)
        view = mInflater.inflate(R.layout.list_item_quotation, parent, false);

    final TextView newTextView = (TextView) view.findViewById(R.id.newTextView);

    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mCallbacks != null)
                mCallbacks.onItemSelected(quotation.id);
            if (!quotation.isRead()) {
                servicesSingleton.setQuotationStatusReadRequest(quotation.id);
                quotation.setStatusRead();
                newTextView.setVisibility(View.GONE);
            }
        }
    });

    if(quotation.isRead())
        newTextView.setVisibility(View.GONE);
    else
        newTextView.setVisibility(View.VISIBLE);

    return view;
}

Le cadre utilise automatiquement le bon position et vous devez vous soucier de le récupérer à nouveau avant d'appeler getView .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X