Przy zamiast po kolei klikając 1,2,3,4,5,6...121, pojawiaja się losowe liczby 1,4,10 itp.
Widoki dla elementów w liscie sa recyclowane, to znaczy że ten sam widok może sie pojawić w różnych miejscach, te dwie sytacjie w getView rozróżnia sie if'em na convertView - jeżeli jest null tworzysz nową instancje widoku w przeciwnym wpadku tylko ustawiasz (bindujesz)odpowiednie wartości (widok jest używany ponownie - można powiedzieć że jest przesuwany na inną pozycje). I tak mniej wiecej robisz ale masz coś takiego:
public View getView(int position, View convertView, final ViewGroup parent) {
ViewHolder holder;
if(convertView==null)
{
// ... cut (tworzenie widoku) ...
final int costam = position;
holder.ZadanieCheckbox.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Zadanie bean = (Zadanie) iLista.get(costam);
if (bean.IsFinished()) bean.ZmienStatus(Zadanie.STATUS_ACTIVE);
else bean.ZmienStatus(Zadanie.STATUS_FINISHED);
Toast.makeText(context, "ID:"+costam, Toast.LENGTH_SHORT).show();
}
});
} else {
// ... cut (pobranie holdera) ...
}
// ... cut (ustawienie stanu) ...
}
Tworzenie listenera na onClick jest u Ciebie robione na tworzniu widoko, tam tworzysz instancje klasy anonimowej która "przechwytuje" (capture) zmienne final w momencie tworzenia (generalnie kompilator generuje nowa klase która w konstruktorze dostaje wszystkie zmienne typu final i instancje klasy zewnetrznej), czyli ten listener ma swoje pole costam i z niego czyta to wartość którą używasz w onClikc. Ponieważ instancje listenera sa tworzone raz to po recycle zostaje Ci ten sam listener który ma zapisane originalną (początkowa) wartość pozycji (w zmiennej costam).
Najprosciej to poprawić przesuwając ten kod do tej częsci ustawianie stanu, czyli uzyskasz coś takiego:
public View getView(int position, View convertView, final ViewGroup parent) {
ViewHolder holder;
if(convertView==null)
{
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.am_listview_row, null);
holder.ZadanieCheckbox = (CheckBox) convertView.findViewById(R.id.zakonczenie_zadania);
holder.ZadanieTytul = (TextView) convertView.findViewById(R.id.nazwa_zadania);
holder.ZadanieData = (TextView) convertView.findViewById(R.id.data_zakonczenia);
convertView.setTag(holder);
}
else
{
holder=(ViewHolder)convertView.getTag();
}
Zadanie bean = (Zadanie) iLista.get(position);
holder.ZadanieCheckbox.setChecked(bean.IsFinished());
holder.ZadanieTytul.setText(bean.PobierzNazwe());
holder.ZadanieData.setText(bean.PobierzDate());
final int costam = position;
holder.ZadanieCheckbox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Zadanie bean = (Zadanie) iLista.get(costam);
if (bean.IsFinished()) bean.ZmienStatus(Zadanie.STATUS_ACTIVE);
else bean.ZmienStatus(Zadanie.STATUS_FINISHED);
Toast.makeText(context, "ID:"+costam, Toast.LENGTH_SHORT).show();
}
});
holder.ZadanieCheckbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// Toast.makeText(context, "ID:"+costam, Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
No i to oczywiscie zadziała ale takie rozwiązanie jest słabe bo alokujesz czesto obiekty przy przewijaniu wiec GC zacznie przycinać. Zeby tyle nie alokować można zrobić tak. W adapterze zaimplementować interfejsy potrzebnych listenerów, do holder dodać pole itemPosition które będzie zmieniane w czasie bindowania a w czasie tworzenie, holder ustawisz również jako tag checkboxa a jako listener podepniesz this'a. Czyli uzyskasz coś takiego:
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ViewHolder holder = (ViewHolder) v.getTag();
Toast.makeText(context, "ID:"+holder.position, Toast.LENGTH_SHORT).show();
}
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
Zadanie bean = (Zadanie) iLista.get(holder.position);
if (bean.IsFinished()) {
bean.zmienStatus(Zadanie.STATUS_ACTIVE);
} else {
bean.zmienStatus(Zadanie.STATUS_FINISHED);
}
Toast.makeText(context, "ID:"+holder.position, Toast.LENGTH_SHORT).show();
}
public View getView(int position, View convertView, final ViewGroup parent) {
ViewHolder holder;
if (convertView==null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.am_listview_row, null);
holder.zadanieCheckbox = (CheckBox) convertView.findViewById(R.id.zakonczenie_zadania);
holder.zadanieTytul = (TextView) convertView.findViewById(R.id.nazwa_zadania);
holder.zadanieData = (TextView) convertView.findViewById(R.id.data_zakonczenia);
holder.zadanieCheckbox.setTag(holder);
convertView.setTag(holder);
holder.zadanieCheckbox.setOnClickListener(this);
holder.zadanieCheckbox.setOnCheckedChangeListener(this);
} else {
holder = (ViewHolder) convertView.getTag();
}
Zadanie bean = (Zadanie) iLista.get(position);
holder.zadanieCheckbox.setChecked(bean.IsFinished());
holder.zadanieTytul.setText(bean.PobierzNazwe());
holder.zadanieData.setText(bean.PobierzDate());
holder.itemPosition = position;
return convertView;
}