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 ?
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 ?
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.
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.
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.
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
.
@hadi vous devriez jeter un coup d'oeil à cette réponse : stackoverflow.com/a/11568271/858626
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);
}
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 );
}
}
}
}
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 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.