ListView getChildAt renvoie null pour les enfants visibles

Je reçois un comportement étrange de la méthode listview / getChildAt.

J’ai un HashSet, iconsToUpdate, des icons qui ont été modifiées dans la firebase database. Je veux parcourir les lignes visibles pour voir si l’une de leurs icons doit être mise à jour pour refléter les nouvelles icons. Je n’ai pas besoin de tester les icons non visibles car elles seront dessinées correctement lors du rendu.

Mon problème est que getChildAt renvoie null quand il semble que ce ne devrait pas être le cas. Je sais que getChildAt ne peut que renvoyer des vues actuellement visibles, mais il renvoie null pour certaines des lignes visibles.

Voici mon code qui parcourt les lignes visibles:

Logger.debug("First visible index: " + f_listView.getFirstVisiblePosition()); Logger.debug("Last visible index: " + f_listView.getLastVisiblePosition()); for (int i = f_listView.getFirstVisiblePosition(); i <= f_listView.getLastVisiblePosition(); i++) { String tag = "asdf"; // Remove when bug is fixed. if (f_listView == null) { Logger.debug("f_listView is null"); } else if (f_listView.getChildAt(i) == null) { Logger.debug("Child at index " + i + " is null"); } else { tag = (String) f_listView.getChildAt(i).getTag(); Logger.debug("Successful at index " + i + ", tag is: " + tag); } if (iconsToUpdate.contains(tag)) { setIcon(i, f_aim.getInHouseIcon(tag)); } } 

Voici le journal correspondant à une exécution de cette boucle:

 D/...: First visible index: 3 D/...: Last visible index: 8 D/...: Successful at index 3, tag is: ... D/...: Successful at index 4, tag is: ... D/...: Successful at index 5, tag is: ... D/...: Child at index 6 is null D/...: Child at index 7 is null D/...: Child at index 8 is null 

Il convient de noter que les premier et dernier index visibles sont correctement signalés, car je visualise les lignes 3 à 8 lorsque je lance ceci. Les lignes 6, 7 et 8 sont correctement rendues. Comment sont-ils affichés s’ils sont nuls?

En outre, je ne sais pas si cela est important, mais la ligne 5 est la dernière ligne visible lorsque je suis en haut de la liste.

Toute information sur la raison pour laquelle ces lignes sont renvoyées comme null serait grandement appréciée.

Merci!

listView.getChildAt (i) fonctionne où 0 est la toute première ligne visible et (n-1) la dernière ligne visible (où n représente le nombre de vues visibles que vous voyez).

Le get last / first visible renvoie la position dans le dataAdapter que vous avez. Donc, depuis que vous commencez à la position 3, avec ce qui ressemble à 6 vues visibles, c’est à ce moment-là que vous obtenez les positions 6-8, vous obtenez nul.

Dans votre exemple, getChildAt (0) renverrait la position 3. En général, je stocke la position sur mes vues afin de pouvoir rechercher mon dataAdapter ultérieurement si j’ai besoin de valeurs.

Je pense que votre pour la boucle devrait ressembler à ceci:

 for (int i = 0; i <= f_listView.getLastVisiblePosition() - f_listView.getFirstVisiblePosition(); i++) 

J'espère que cela t'aides.

Essayer

 f_listView.getChildAt(positionOfChildYouWantGet - f_listView.getFirstVisiblePosition()); 

Lorsque vous appelez listView1.getLastVisiblePosition() et listView1.getFirstVisiblePosition() , la listview renvoie les positions des éléments partiellement visibles dans la vue de liste. Par exemple, le premier élément peut être à moitié visible et le dernier élément peut être à moitié visible. Dans ce cas, même si vous pouvez voir une partie de l’élément dans la vue de liste, l’adaptateur n’a pas encore appelé la fonction getView() pour l’élément et par conséquent, l’élément est toujours considéré comme nul.

Dans mon cas, j’ai un listView et le premier élément est complètement visible mais quand je getFirstVisiblePosition() le résultat est 1!

Cela devient plus étrange quand je fais défiler et que le premier élément est à moitié visible, alors mon getView montre que getFirstVisiblePosition() a la valeur 0.

ceci mon code:

 public View getView(final int position, View convertView, final ViewGroup parent) { row = convertView; final AtomPaymentHolder holder = new AtomPaymentHolder(); LayoutInflater inflater = ((Activity) context).getLayoutInflater(); row = inflater.inflate(layoutResourceId, parent, false); row.setTag(items.get(position)); holder.songitem = items.get(position); final int firstPosition = MainActivity.listviewSong.getFirstVisiblePosition() - MainActivity.listviewSong.getHeaderViewsCount(); final int lastPosition = MainActivity.listviewSong.getLastVisiblePosition(); if(MusicService.indexService>= firstPosition && MusicService.indexService<= lastPosition){ MainActivity.listviewSong.getChildAt(MusicService.indexService-firstPosition).setBackgroundColor(getContext().getResources().getColor(R.color.pressed_color)); } 

(Quand j'ai sélectionné l'élément suivant et que je fais défiler, cela fonctionne bien)

Ils sont partiellement visibles peut-être. Mais lorsque getView () essaie de recycler les vues, celles-ci deviennent totalement visibles, les autres les considèrent comme nulles. Par exemple, si vous faites défiler la liste et que l’élément supérieur est partiellement visible et que le bas est partiellement visible, ces éléments sont nuls, mais vous les voyez toujours.

J’ai essayé par la moyenne dans OnListItemClickListener (), mais échoue. Enfin, j’ai apporté des modifications à mon adaptateur personnalisé pour listview. Ici, dans getView (), j’applique clickListener sur l’élément que j’ai ajouté fréquemment à la liste. n faire toutes les fonctionnalités requirejses là-bas. Voici mon code, où j’ajoute Image View dans la liste n alors appliquez l’écouteur sur imageview.

Je pense que cela aidera ceux qui veulent changer de couleur lorsque certains éléments de la liste sont> sélectionnés. Fonce..

Dans getView () de l’adaptateur personnalisé // ——————————— code ——- ———————————–


LayoutInflater inflater = (LayoutInflater) contexte
.getSystemService (Context.LAYOUT_INFLATER_SERVICE);

View rowView = inflater.inflate(R.layout.icon_image_layout, parent, false); ImageView imageView = (ImageView) rowView.findViewById(R.id.Icon_ImageView); imageView.setClickable(true); final int pos=position; imageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub // TODO Auto-generated method stub try{ if(previous_view!=null) previous_view.setBackgroundColor(Color.WHITE); }catch (Exception e) { System.out.println("Exception Occurs Previous View"); } v.setBackgroundColor(Color.RED); MainActivity.imageView.setImageResource(MainActivity.Image_Name[pos]); previous_view=v; return false; } });

Je sais que c’est très ancien post. Mais je réponds parce que les gens sont toujours à la recherche d’un travail autour de l’exception de pointeur null ListView getChildAt() .

Cela est dû au fait que ArrayApdater REMOVING et RECYCLING les vues qui ne sont pas encore visibles sur ListView en raison de la hauteur. Donc, si vous avez 10 vues d’éléments et que ListView peut afficher 4 à 5 à la fois:

L’adaptateur SUPPRIME les vues d’élément à la position 5 à 9, de sorte que toute tentative d’ adapter.getChildAt(5... to 9) provoque une exception de pointeur nul

L’adaptateur RECYCLE également la vue de l’article, de sorte que toute référence que vous avez faite à la position 3, par exemple, sera perdue lorsque vous faites défiler de 5 à 9 et que toute entrée de la position 3 (EditText, Checkbox, etc.) sera être recyclé lorsque vous faites défiler de 5 à 9 et sera réutilisé ultérieurement (ex position 1, 2 ou 3, etc.) avec la même valeur

Le seul moyen que j’ai trouvé pour contrôler cela est d’oublier d’obtenir la vue et d’avoir:

Atsortingbut HashMap iconViews ou tout type que vous souhaitez utiliser pour gérer les valeurs que vous souhaitez utiliser pour chaque élément de la liste. Le premier type doit être unique pour l’élément comme item->getId() ou position . Initialisez-le avec le new HashMap<>() dans le constructeur; Dans getViews, faites iconViews.put(position, iconView); Empêcher l’Adaptateur d’utiliser convertView convert, supprimer la condition if(convertView == null) afin que l’adaptateur gonfle toujours une nouvelle instance de vue. Étant donné que l’instance de vue est nouvelle à chaque fois, vous devez également définir la valeur à partir de HashMap comme si elle contenait déjà la clé if(iconViews.containsKey(position)){iconView = iconViews.get(position))}; . Probablement dans ce cas, il n’y a pas des tonnes d’objects, de sorte que le défilement régulier ne sera pas un must.

Et enfin créer des méthodes publiques pour obtenir les valeurs en dehors de Adapter passant item->getId() Integer comme paramètre. Ex: public ImageView getIconViewAt(int position) { return iconViews.get(position); } public ImageView getIconViewAt(int position) { return iconViews.get(position); } . Il sera alors facile de sélectionner un élément de l’adaptateur

Voir plus de ma réponse .

N’est-ce pas parce que vous dites

 f_listView.getChildAt(i) 

Et vous devriez récupérer l’article à cette position?

 f_listView.getItemAtPosition(i)