Wpis z mikrobloga

#java #android #adaptery

Mirki pomożecie? Mam problem z ListView.

Sprawa wygląda następująco:

- Po kliknięciu na element lisy, dany element zmienia stan (powiększa się itd).

- Adapter listy to własny adapter rozszerzający klasę Base Adapter.

Rozwiązałem to w tak:

- Po kliknięciu na element wywoływana jest metoda notifyDataSetChanged();

- Adapter na nowo przelatuje listę

- W metodzie getView() rozróżniam czy element został kliknięty i na podstawie tego decyduję czy pozostawić poprzedni stan czy zmienić parametry.

Sposób prosty i szybki, ale oczywiście jest problem. Bo gdy wywoływana jest metoda getView() i chce zwrócić poprzedni stan (poprzez return convertView) adapter czasami zwraca błędne View tzn inny element niż powinien być na danej pozycji. Dzieje się to tylko w momencie kiedy lista jest przesuwana.

Doszedłem do wniosku, że adapter niepoprawnie przechowuje elementy lisy. Zrobiłem więc tablicę View[] i w niej trzymam wszystkie elementy.

Rozwiązało to problem dublujących się elementów listy, ale teraz problemem jest co innego.

Metody onClick w danych elementach listy czasami nie działają. Nie widzę tu jakiejś prawidłowości. Po prostu wygląda to jak by było to losowe.

I w tym momencie opadają mi witki i robię typowe WTF. Obydwa rozwiązania nie działają prawidłowo i nie mam pomysłu jak to rozwiązać.

Mirkowe eksperty doradźcie bo walczę z tym od dłuższego czasu, a ani Google i StackOverflow pytane nie chcą konkretnie odpowiedzieć.
  • 7
@maciejkiner: Proszę http://pastebin.com/YLiWugwu

Dałem tam wersję z pierwszym rozwiązaniem.

Konstrukcja if to mniej więcej takie coś:

if (jestToKlikniętaPozycja lub pierwsza iteracja) {

// inicjacja poszczególnych elementów

// wyświetlanie lub chowanie detailsLay - LineraLayout

// zwraca poprawiony view

} else {

// zwraca niezmieniony stan

}

Czyli ładuję ten sam layout ale zmieniam jego stan
@siemanko: musiałbyś to rozbić na dwa osobne templaty, nadpisujesz wtedy getViewTypeCount() i getView(int position, View v, ViewGroup parent) w adapterze. Albo wewnątrz tego ifa gdzie zwracasz niezmieniony stan upewnić się, że ten niezmieniony jest poprawny (nie wiem co tam siedzi w initAnimations() ale może po prostu to tam wywołać, żeby ustawić poprawny wygląd wiersza). Ja u siebie w getView() robię takie coś:

LinkViewHolder holder = new LinkViewHolder();

if (v == null)
@b0lec: Niestety niewolno mi:/

@maciejkiner: Rozwiązanie wydaje się logiczne. Ale czy przypadkiem opcja z holderem nie jest tym samym co trzymanie view w tablicy?

Zrobiłem tak :

metoda getView()

if (position == clickedPos) {

View vi = initRow(position); // tutaj zmieniam ifami wlasiciwie jeden element View.GONE / View.VISIBLE

views[position] = vi;

return vi;

} else {

return views[position];

}

I tutaj nie ma problemu z poprawnym trzymaniem view, ale za
@siemanko: no ta tablica z View działa pewnie podobnie, ale holder chyba mniej pamięci konsumuje. Spróbuj może zrobić to najbardziej topornie jak się da (za każdym razem na nowo tworzyć widok, aktualizować dane i podpinać eventy). Będzie to niezbyt wydajne ale wszystko powinno działać (w końcu zawsze wymuszasz podpięcie wszystkiego do aktualnie wyświetlanych elementów). Potem będziesz optymalizował, jak zadziała ;)

Tu też jest dobry tutorial.
@maciejkiner: Udało się! Tablica z Viewami działa ok. A co do listenerów to wystarczyło przy inicjacji każdego dać view.SetTag() i później go odczytywać. Przyznam, że dziwne to, ale pomogło.

Lars Vogel zawsze na propsie i trzeba będzie przerobić jego tutka bo widzę spore braki mam.

Muszę także przyjrzeć się tym holderom. Jeśli mówisz, że są bardziej wydajne to na pewno będzie przydatne. Dzięki za pomoc:)