ListView getChildAt gibt null für sichtbare untergeordnete Elemente zurück

Ich bekomme seltsames Verhalten von einer ListView / getChildAt Methode.

Ich habe ein HashSet, iconsToUpdate, von Icons, die in der database geändert wurden. Ich möchte über die sichtbaren Zeilen iterieren, um zu sehen, ob eines ihrer Symbole aktualisiert werden muss, um die neuen Symbole wiederzugeben. Ich muss die Icons, die momentan nicht angezeigt werden, nicht testen, da sie beim Rendern korrekt gezeichnet werden.

Mein Problem ist, dass getChildAt null zurückgibt, wenn es so aussieht, als ob es nicht sollte. Ich weiß, dass getChildAt nur Ansichten zurückgeben kann, die derzeit sichtbar sind, aber für einige der sichtbaren Zeilen null zurückgibt.

Hier ist mein Code, der über die sichtbaren Zeilen iteriert:

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)); } } 

Hier ist das Protokoll, das einem Lauf dieser Schleife entspricht:

 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 

Es sollte beachtet werden, dass die ersten und letzten sichtbaren Indizes korrekt gemeldet werden, da ich die Zeilen 3-8 beim Ausführen dieses Vorgangs sehe. Zeilen 6, 7, 8 werden ordnungsgemäß gerendert. Wie werden sie angezeigt, wenn sie null sind?

Außerdem weiß ich nicht, ob das wichtig ist, aber Zeile 5 ist die letzte sichtbare Zeile, wenn ich oben in der Listenansicht bin.

Jede Information darüber, warum diese Zeilen als Null zurückgegeben werden, würde sehr geschätzt werden.

Vielen Dank!

listView.getChildAt (i) funktioniert, wobei 0 die erste sichtbare Zeile und (n-1) die letzte sichtbare Zeile ist (wobei n die Anzahl der sichtbaren Ansichten ist, die Sie sehen).

Die get last / first visible geben die Position im DataAdapter zurück, die Sie haben. Also, seit du an Position 3 beginnst, mit dem, was wie 6 sichtbare Ansichten aussieht, dann bekommst du für die Positionen 6-8 null.

In Ihrem Beispiel würde getChildAt (0) die Position 3 zurückgeben. Was ich normalerweise mache, ist die Position in meinen Ansichten zu speichern, damit ich später auf meinem dataAdapter nachsehen kann, wenn ich Werte brauche.

Ich denke, deine For-Schleife sollte so aussehen:

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

Hoffe das hilft.

Versuchen

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

Wenn Sie listView1.getLastVisiblePosition() und listView1.getFirstVisiblePosition() listview gibt die listview die Positionen der Elemente zurück, die in der Listenansicht teilweise sichtbar sind. Zum Beispiel kann das erste Element halb sichtbar sein und das letzte Element kann halb sichtbar sein. In diesem Fall hat der Adapter die function getView() für das Element noch nicht aufgerufen, obwohl Sie einen Teil des Elements in der Listenansicht sehen können. Daher wird das Element immer noch als null betrachtet.

In meinem Fall habe ich eine listView und das erste Element ist voll sichtbar, aber wenn ich getFirstVisiblePosition() das Ergebnis ist 1!

Es wird komischer, wenn ich blättern und das erste Element halb sichtbar getView , dann zeigt mein getView , dass getFirstVisiblePosition() 0 ist.

das ist mein 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)); } 

(wenn ich das nächste Element auswähle und scrolle, funktioniert es gut)

Sie sind vielleicht teilweise sichtbar. Aber wenn das getView () versucht, die Ansichten zu recyceln, wird es VOLL sichtbar angezeigt, andere nehmen sie als null. Wenn Sie zum Beispiel die Liste scrollen und das oberste Element teilweise sichtbar ist und das untere Teil teilweise sichtbar ist, sind dies Nullen, aber Sie sehen sie immer noch.

Ich probierte immer in OnListItemClickListener (), aber scheitert. Endlich habe ich einige Änderungen in meinem angepassten Adapter für Listview vorgenommen. Hier verwende ich in getView () clickListener auf das Objekt, das ich häufig in die Liste eingefügt habe. n alle erforderlichen functionen dort ausführen. Hier ist mein Code, wo ich die Bildansicht in der Liste n hinzufüge, also den Listener auf imageview anwende.

Ich denke, es wird denjenigen helfen, die die Farbe ändern möchten, wenn ein bestimmtes Listenelement ausgewählt ist. Tue es..

In getView () von angepassten Adapter // ——————————— Code ——- ———————————–


LayoutInflater inflater = (LayoutInflater) Kontext
.getSystemService (Kontext.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; } });

Ich weiß, das ist eine sehr alte Post. Aber ich antworte, weil Leute immer noch nach einer ListView getChildAt() Nullzeigerausnahme suchen.

Dies liegt daran, dass der ArrayApdater die Ansichten entfernt und RECYCLINGt, die auf der ListView aufgrund der Höhe noch nicht sichtbar sind. Wenn Sie also 10 Artikelansichten haben und ListView kann gleichzeitig 4 – 5 anzeigen:

Der Adapter ENTFERNT die Objektansichten an den Positionen 5 bis 9, so dass jeder Versuch, adapter.getChildAt(5... to 9) eine Nullzeiger-Ausnahme adapter.getChildAt(5... to 9)

Der Adapter RECYCLE auch die Objektansicht, so dass alle Referenzen, die Sie zum Beispiel an Position 3 gemacht haben, verloren gehen, wenn Sie auf 5 bis 9 runterscrollen, und auch alle Eingaben, die Sie an Position 3 vornehmen (EditText, Checkbox, etc.) recycelt werden, wenn Sie zu 5 bis 9 scrollen und später an einer anderen Position (ex 1, 2 oder 3, usw.) mit dem gleichen Wert wiederverwendet werden

Der einzige Weg, den ich gefunden habe, um dies zu kontrollieren, besteht darin, die Ansicht zu vergessen und zu haben:

Attribut HashMap iconViews oder ein beliebiger Typ für die Behandlung der Werte, die Sie für jedes Element in der Liste verwenden möchten. Der erste Typ muss für Artikel wie item->getId() oder position eindeutig sein. Initialisiere es mit dem new HashMap<>() im Konstruktor; in getViews make iconViews.put(position, iconView); Verhindere, dass der Adapter recycelte convertView verwendet, entferne die Bedingung if(convertView == null) damit der Adapter immer eine brandneue Ansichtsinstanz aufbläht. Da die View-Instanz jedes Mal neu ist, müssen Sie den Wert von HashMap auch jedes Mal if(iconViews.containsKey(position)){iconView = iconViews.get(position))}; wenn er bereits den Schlüssel if(iconViews.containsKey(position)){iconView = iconViews.get(position))}; enthält if(iconViews.containsKey(position)){iconView = iconViews.get(position))}; . Wahrscheinlich gibt es in diesem Fall nicht Tonnen von Items, so dass ein reibungsloses Scrollen kein Muss ist.

Und schließlich erstellen Sie öffentliche Methoden, um die Werte außerhalb des Adapters zu erhalten, übergeben Sie item->getId() Integer als Parameter. Beispiel: public ImageView getIconViewAt(int position) { return iconViews.get(position); } public ImageView getIconViewAt(int position) { return iconViews.get(position); } . Es wird dann einfach sein, Artikel vom Adapter auszuwählen

Siehe mehr von meiner Antwort .

Ist es nicht weil du sagst?

 f_listView.getChildAt(i) 

Und Sie sollten den Gegenstand an dieser Position abrufen?

 f_listView.getItemAtPosition(i)