Więc mam ten problem miałem przed i naturalnie poprosiłem o pomoc na tutaj . Odpowiedź Luksprog była świetna, ponieważ nie miałem pojęcia, jak ListView i GridView zoptymalizowały się dzięki recyklingowi widoków. Dzięki jego radom mogłem zmienić sposób dodawania widoków do mojego widoku GridView. Problem w tym, że mam teraz coś, co nie ma sensu. To jest moje getView
z mojego BaseAdapter
:
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.day_view_item, parent, false);
}
Log.d("DayViewActivity", "Position is: "+position);
((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);
//layout.addView(new EventFrame(parent.getContext()));
TextView create = new TextView(DayViewActivity.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
create.setLayoutParams(params);
create.setBackgroundColor(Color.BLUE);
create.setText("Test");
//the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
//new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)
if(position == 0) {
Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
layout.addView(create);
}
return convertView;
}
}
Problem polega na tym, że kiedy przewijam, dzieje się tak, a nie na pozycji 0 ... Wygląda na to, że pozycja 6 i pozycja 8, plus umieszcza dwie na pozycji 8. Teraz wciąż próbuję zawiesić korzystanie z ListView i GridView, więc robię nie rozumiem, dlaczego tak się dzieje. Jednym z głównych powodów , dla których zadaję to pytanie, jest pomoc innym, którzy prawdopodobnie nie wiedzą o ListView i widoku recyklingu GridView lub o mechanizmie ScrapView, jak to ujęto w tym artykule .
Później Edytuj
Dodanie linku do rozmowy Google IO, czyli w zasadzie wszystko, czego potrzebujesz, aby zrozumieć, jak działa ListView. Link nie zdawał sobie sprawy z komentarzy. Więc user3427079 był na tyle miły, że zaktualizował ten link. Tutaj jest dla łatwego dostępu.
0
).ListView
pojawi się potrzeba nowego wiersza (np. Kontynuowanie przewijania w dół / w górę). Problem w tym, że widok, który po prostu zniknął i będzie używany na przyszłych potrzebnych stanowiskach,TextView
już do niego dodano, to jest problem. Aby go rozwiązać, musisz usunąć go zgetView
metody, jeśligetView
metoda jest wywoływana dla innej pozycji niż0
.Odpowiedzi:
Początkowo nie zdawałem sobie sprawy z recyklingu listview i mechanizmu użycia convertview, ale po całodniowych badaniach prawie rozumiem mechanizmy widoku listy, odwołując się do obrazu z android.amberfog
Za każdym razem, gdy widok listy jest wypełniany przez adapter, w zasadzie pokazuje liczbę wierszy, które widok listy może wyświetlić na ekranie, a liczba wierszy nie zwiększa się nawet podczas przewijania listy. To jest sztuczka, której używa Android, aby wyświetlić listę działającą wydajniej i szybciej. Teraz wewnętrzna historia listview odnosząca się do obrazu, jak widać, początkowo listview ma 7 widocznych elementów, a następnie, jeśli przewiniesz w górę, aż element 1 nie będzie już widoczny, getView () przekaże ten widok (tj. Element1) do recykler i możesz użyć
wewnątrz twojego
Zauważysz, że w swoim logcat początkowo convertview ma wartość null dla wszystkich widocznych wierszy, ponieważ początkowo w recyklerze nie było żadnych widoków (tj. Elementów), więc funkcja getView () tworzy nowy widok dla każdego z widocznych elementów, ale gdy przewiniesz w górę i pozycja 1 wyjdzie z ekranu, zostanie wysłana do Recyklera ze swoim obecnym stanem (na przykład tekst TextView lub w moim przypadku, jeśli pole wyboru jest zaznaczone, zostanie skojarzone z widokiem i przechowywane w recyklerze).
Teraz, kiedy przewiniesz w górę / w dół, twój widok listy nie utworzy nowego widoku, użyje widoku, który jest w twoim recyklerze. W swojej logcat można zauważyć, że „convertView” nie jest null, jej, ponieważ nowa pozycja 8 zostanie opracowany przy użyciu convertview, czyli w zasadzie zajmuje pozycję 1 widok z recyklera i nadmuchuje pkt 8 na swoim miejscu, i można obserwować to w moim kodzie. Jeśli miałeś pole wyboru i jeśli zaznaczysz je na pozycji 0 (powiedzmy, że item1 miał checkbox i zaznaczyłeś je), więc kiedy przewiniesz w dół, zobaczysz pole wyboru item 8 już zaznaczone, to dlatego listview ponownie używa tego samego widoku, nie tworzy nowego dla Ciebie ze względu na optymalizację wydajności.
Ważne sprawy
1 . Nigdy nie ustawiaj
layout_height
andlayout_width
of your listview na,wrap_content
ponieważgetView()
zmusi twój adapter do uzyskania dziecka do pomiaru wysokości widoków do narysowania w widoku listy i może spowodować nieoczekiwane zachowanie, takie jak zwracanie Convertview, nawet jeśli lista nie jest przewijana. Zawsze używajmatch_parent
lub naprawione szerokość wysokość.2 . Jeśli chcesz użyć jakiegoś układu lub widok po widoku listy i pytanie może przyszedł w swoim umyśle, jeśli ustawić
layout_height
dofill_parent
widoku po widoku listy nie pojawi się, jak to idzie w dół ekranu, tak że lepiej postawić ListView wewnątrz Na przykład układ liniowy i ustaw wysokość i szerokość tego układu zgodnie z wymaganiami i ustaw atrybut wysokości i szerokości widoku listy na stan układu (np. jeśli szerokość układu wynosi 320, a wysokość 280), to widok listy powinny mieć taką samą wysokość i szerokość. To powie getView () o dokładnej wysokości i szerokości widoków do renderowania, a getView () nie będzie wywoływać raz po raz niektórych losowych wierszy i innych problemów, takich jak zwracanie widoku konwersji nawet przed przewijaniem, mam test to ja, chyba że mój widok listy znajdował się wewnątrz lineaLayout, miał również problemy, takie jak powtarzanie wywołania widoku i konwersja widoku jako, umieszczenie Listview wewnątrz LinearLayout działało dla mnie jak magia. (nie wiedziałem dlaczego)Ale teraz jest już rozwiązany, wiem, nie jestem dobry w wyjaśnianiu, ale ponieważ poświęcam cały dzień na zrozumienie, więc pomyślałem, że inni początkujący, tacy jak ja, mogą uzyskać pomoc z mojego doświadczenia i mam nadzieję, że teraz wy trochę zrozumiecie z ListView ramach, jak to działa, jak to jest naprawdę brudny i znalazł zbyt wiele problemu ze zrozumieniem go tak skomplikowane początkujących
źródło
if you had a checkbox and if you check it at position 0(let say item1 has also a checkbox and you checked it) so when you scroll down you will see item 8 checkbox is already checked,this is why listview is re using the same view not creating a new for you due to performance optimization.
abym zrozumiał mój błąd. Najlepszy post o recyklingu Android ListView, na jaki trafiłem!RecyclerView
działa również na tym samym mechanizmie? W moim pytaniu stackoverflow.com/questions/47897770/… , wiem, że zadanie jest ciche i niemożliwelistView
. Powinienem spróbowaćrecyclerView
?Uważaj, we wzorcu Holder, jeśli ustawiasz pozycję w swoim obiekcie Holder, powinieneś ustawić ją za każdym razem, na przykład:
to jest przykład z klasy abstrakcyjnej, gdzie
wykonuje wszystkie operacje ustawień dla
źródło
parent.setTag(holder);
zamiast poprawnego sposobu, który jestview.setTag(holder);
Używając wzoru Holder możesz osiągnąć to, co chcesz:
Opis tego wzoru można znaleźć tutaj:
Recykling widoku listy ma miejsce, gdy przewijasz ekran w dół, a elementy widoku listy powyżej są ukryte. Są one ponownie wykorzystywane do wyświetlania nowych elementów widoku listy.
źródło