ListView pas rafraîchissant déjà les éléments visibles
J'affiche une liste de contacts (nom + image) à l'aide de la ListView
. Afin de rendre la charge initiale rapide, je ne charge que les noms d'abord, et de reporter l'image de chargement. Maintenant, chaque fois que mon thread d'arrière-plan des finitions de chargement d'une image, il planifie ma carte notifyDataSetChanged()
d'être appelé sur le thread d'INTERFACE utilisateur. Malheureusement, lorsque cela arrive, le ListView
de ne pas re-rendu (c'est à dire appel getView()
pour) les éléments qui sont déjà à l'écran. De ce fait, l'utilisateur ne voit pas la nouvelle image chargée, à moins qu'ils défilement et de retour pour les mêmes articles, de sorte que les points de vue sont recyclés. Quelques morceaux de code:
private final Map<Long, Bitmap> avatars = new HashMap<Long, Bitmap>();
//this is called *on the UI thread* by the background thread
@Override
public void onAvatarLoaded(long contactId, Bitmap avatar) {
avatars.put(requestCode, avatar);
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//snip...
final Bitmap avatar = avatars.get(contact.id);
if (avatar != null) {
tag.avatar.setImageBitmap(avatar);
tag.avatar.setVisibility(View.VISIBLE);
tag.defaultAvatar.setVisibility(View.GONE);
} else {
tag.avatar.setVisibility(View.GONE);
tag.defaultAvatar.setVisibility(View.VISIBLE);
if (!avatars.containsKey(contact.id)) {
avatars.put(contact.id, null);
//schedule the picture to be loaded
avatarLoader.addContact(contact.id, contact.id);
}
}
}
AFAICT, si vous supposez que notifyDataSetChanged()
causes les éléments de l'écran pour être re-créé, mon code est correct. Cependant, il semble que n'est pas vrai, ou peut-être que je suis absent quelque chose. Comment puis-je faire ce travail en douceur?
- mieux de prendre un regard sur certains ImageLoader source ...1. set ID à la balise de ImageView 2. exécuter chargeur avec ImageView(comme la semaine ref) et l'ID que params 3. lorsque le chargeur de finir de télécharger et de décoder bitmap passer ImageView, Id et bitmap à une fonction gérée sur le thread de l'INTERFACE utilisateur 4. comparer Balise de ImageView avec ID (depuis ImageView pourraient être réutilisés) si elles sont de la même série ImageView avec le Bitmap ... vous pouvez aussi essayer d'appeler ListView.invalidateViews() pour mettre à jour visible LV éléments
- Je suis à l'aide d'une classe dérivée de
BaseAdapter
, et je suis déjà en appelantnotifyDataSetChanged()
manuellement. De sorte que la réponse ne s'applique pas à moi. - Peut-être essayer d'appeler
notifyDataSetInvalidated()
- J'ai aussi pensé à garder la trace de mes
ImageView
s et changer leur image bitmap directement, sans s'appuyer surgetView
. Mais il semble plutôt compliqué. Surtout depuis que mon code est un peu plus compliqué que je ne vais pas changer juste leImageView
, je vais changer d'autres choses (de la part de plusieurs sources de données). Je préfère avoir tous mes articles-rendu de code dansgetView
. - avez-vous lu la JavaDoc sur qui? Voici ce qu'il dit:
Notifies the attached observers that the underlying data is no longer valid or available. Once invoked this adapter is no longer valid and should not report further data set changes.
-- j'aimerais continuer à utiliser mon adaptateur. - Maintenant que j'y pense, je me souviens avoir eu des problèmes similaires concernant la mise à jour d'une liste. Quelle est la version d'Android que vous utilisez?
- 4.3 (Nexus 4). J'ai juste essayé d'appeler
invalidateViews()
sur leListView
aprèsnotifyDataSetChanged()
, mais il semble que la JavaDoc est source de confusion, car il ne s'est toujours pas fait redessiner le déjà des éléments de l'écran. - Ce problème semble très similaire à ce que j'ai (post ici: stackoverflow.com/questions/25243341/... ) . Disposez-vous également de la notifyDataSetChanged mise à jour de tous les points de vue, sauf pour le point de vue qui a un événement tactile ?
Vous devez vous connecter pour publier un commentaire.
Ici je vais répondre à ma propre question avec un hackaround que j'ai réglé sur. Apparemment,
notifyDataSetChanged()
n'est à utiliser que si vous êtes l'ajout /suppression d'éléments. Si vous êtes à la mise à jour des informations sur les articles qui sont déjà affichés, vous pourrait jusqu'à la fin avec les éléments visibles de ne pas mettre à jour leur aspect visuel (getView()
pas d'être appelé sur votre carte).Par ailleurs, en appelant
invalidateViews()
sur leListView
ne semble pas fonctionner comme annoncé. J'obtiens toujours la même glitch comportement avecgetView()
pas être appelé à la mise à jour des éléments de l'écran.Au début, je pensais que le problème a été causé par la fréquence à laquelle je les ai appelés
notifyDataSetChanged()
/invalidateViews()
(très rapide, en raison des mises à jour provenant de différentes sources). J'ai donc essayé de limitation des appels à ces méthodes, mais toujours en vain.Je ne suis pas encore sûr à 100% c'est la plate-forme de la faute, mais le fait que mon hackaround œuvres semble le suggérer. Alors, sans plus tarder, mon hackaround consiste en l'extension de la
ListView
pour actualiser les éléments visibles. Notez que cela ne fonctionne que si vous êtes correctement à l'aide de laconvertView
de votre carte et de ne jamais retourner un nouveauView
lorsqu'unconvertView
a été adoptée. Pour des raisons évidentes:notifyDataSetChanged()
que vous avez fait. À partir de là, il se reconstruit (parties de lui-même, corrigez-moi ici si sa l'ensemble de la carte ou il sait exactement ce qui a changé) pour être à jour.Ajoutez la ligne suivante à onResume()
listview.setAdapter(listview.getAdapter());
Selon la documentation:
vide notifyDataSetChanged ()
Notifier toutes les observateurs que l'ensemble de données a changé.
... LayoutManagers sera forcé de pleinement relier et de la nouvelle disposition toutes les vues visibles...
Dans mon cas, les éléments n'étaient pas visibles (ensuite, tout le RecycleView était en dehors de l'écran), et, plus tard, lorsqu'il a animé dans la rubrique points de vue n'a pas d'actualisation soit (montrant ainsi les anciennes données).
Solution de contournement dans la classe d'Adaptateur:
Remplacé tous les appels de notifyDataSetChanged() pour notifyDataSetChanged_fix() et mon RecyclerView heureusement rafraîchissante depuis...