Android ListView ImageButton neues Bild zuweisen funktioniert nicht

Hallo Forum,

Ich habe eine Liste, die mit Rechenergebnissen, bzw. dessen Namen, gefüllt ist. Damit man mehrere Rechnungen gruppieren kann, habe ich ein ImageButton hinzugefügt, das eine Checkbox beinhaltet. Eine Reihe kann man auswählen indem man mit dem onTouchListener und dem onLongClickListener der gesamten View oder mit einem Klick auf den ImageButton seine Auswahl betätigt.
Damit man sieht, dass eine Reihe ausgewählt ist soll der ImageButton ein anderes Bild bekommen, ein „checked“-Bild bekommen und beim entfernen der Auswahl wird es wieder zum „unchecked“-Bild geändert. Dafür habe ich ein ViewHolder eingebaut, damit ich den Button erst anspreche, wenn das Programm schon weiß in welcher Reihe man sich befindet. Sonst wurde nur das Bild in der 0ten Reihe geändert.

Problem: Wenn ich jetzt so viele Rechnungen in meinem Speicher habe, dass ich mehr als 9 habe, funktioniert das System nicht mehr. Wenn ich also Reihe 0 auswähle wird Reihe 10 optisch auch ausgewählt. Das hat keinen Einfluss auf die Listen, die die Auswahl speicher, der Benutzer weiß aber nicht was wirklich ausgewählt ist. Anders herum entsteht das Problem auch. Also z.B. bei Auswahl der Reihe 12 wird Reihe 2 auch ausgewählt.

Wie kann ich dieses Verhalten vermeiden? In der Liste selectedItemIndex steht z.B. auch 12 an der Stelle 12 und nicht 2 an der Stelle 12.

Danke!

public class ArrayAdapterListView extends BaseAdapter {

private final ArrayList<String> arrayList;
private final Context context;
private ArrayList<String> pWListName, pW2ListName;
private ArrayList<Integer> pWListIconID;
private ListPopupWindow listPopupWindow, listPopupWindow2;
private boolean isItemHold = false;
ViewHolder viewHolder = new ViewHolder();
private final
LinearLayout buttonsLayout;

public ArrayAdapterListView(ArrayList<String> list, Context context, LinearLayout linearLayout){
    this.arrayList = list;
    this.context = context;
    this.buttonsLayout = linearLayout;
}


@Override
public int getCount() {
    return arrayList.size();
}

@Override
public Object getItem(int position) {
    return arrayList.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@SuppressLint({"ClickableViewAccessibility", "InflateParams"})
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = convertView;
    if(view == null){
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.fragment_file_browser_row, null);
        viewHolder = createViewHolder(view);
        view.setTag(viewHolder);
    }else{
        viewHolder = (ViewHolder) view.getTag();
    }

    viewHolder.textView.setText(arrayList.get(position));

    if(selectedItemIndex.isEmpty()) {
        for (int i = 0; i < getCount(); i++) {
            selectedItemIndex.add(null);
        }
    }
    if(isItemSelected.isEmpty()){
        for (int i = 0; i < getCount(); i++){
            isItemSelected.add(false);
        }
    }

    view.setOnTouchListener((v, event) -> {
        viewHolder.checkedImage = v.findViewById(R.id.checkedImage);
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            index = position;
            if(L)Log.d("fileBrowser", "index: " + index);
        }

        //Auswahl betätigen
        if (event.getAction() == MotionEvent.ACTION_UP && isItemHold && !isItemSelected.get(index)) {
            isItemHold = false;
            isItemSelected.set(index, true);
            if (L) Log.d("fileBrowser", "isItemSelected: " + isItemSelected);
            selectedItemIndex.set(index, index);
            if(L)Log.d("fileBrowser", "selectedItemIndex: " + selectedItemIndex);

                    viewHolder.checkedImage.setImageResource(R.drawable.ic_checkbox_checked);
        }
        //Auswahl löschen
        else if(event.getAction() == MotionEvent.ACTION_UP &&     isItemSelected.get(index)
                /*&& !isCheckboxClicked.get(index)*/){
            isItemHold = false;
            isItemSelected.set(index, false);
            if (L) Log.d("fileBrowser", "isItemSelected: " + isItemSelected);
            selectedItemIndex.set(index, null);
            if(L)Log.d("fileBrowser", "selectedItemIndex: " + selectedItemIndex);

            viewHolder.checkedImage.setImageResource(R.drawable.ic_checkbox);
        }

        if (isItemSelected.contains(true)){
            buttonsLayout.setVisibility(View.VISIBLE);
            buttonsLayout.animate().translationY(0);
        }else{
            buttonsLayout.animate().translationY(buttonsLayout.getHeight());
            buttonsLayout.setVisibility(View.GONE);
        }

        return false;
    });

    view.setOnLongClickListener(v -> {
        if(!isItemHold) {
            isItemHold = true;
            if(L)Log.d("fileBrowser", "Long Click getätigt: isItemHold = true");
        }
        return false;
    });

    viewHolder.checkedImage.setOnClickListener(v -> {
        View parentRow = (View) v.getParent();
        ListView listView = (ListView) parentRow.getParent();
        index = listView.getPositionForView(parentRow);
        if(L)Log.d("fileBrowser", "Index of parentRow (Button): " + index);

        viewHolder.checkedImage = v.findViewById(R.id.checkedImage);
        if (!isItemSelected.get(index)) {
            if(L)Log.d("fileBrowser", "Auswahl tätigen");
            isItemSelected.set(index, true);
            if (L) Log.d("fileBrowser", "isItemSelected: " + isItemSelected);
            selectedItemIndex.set(index, index);
            if (L)
                Log.d("fileBrowser", "selectedItemIndex: " + selectedItemIndex);
                viewHolder.checkedImage.setImageResource(R.drawable.ic_checkbox_checked);
        } else {
            if(L)Log.d("fileBrowser", "Auswahl löschen");
            isItemSelected.set(index, false);
            if (L) Log.d("fileBrowser", "isItemSelected: " + isItemSelected);
            selectedItemIndex.set(index, null);
            if (L) Log.d("fileBrowser", "selectedItemIndex: " + selectedItemIndex);
            viewHolder.checkedImage.setImageResource(R.drawable.ic_checkbox);
        }

        if (isItemSelected.contains(true)){
            buttonsLayout.setVisibility(View.VISIBLE);
            buttonsLayout.animate().translationY(0);
        }else{
            buttonsLayout.animate().translationY(buttonsLayout.getHeight());
            buttonsLayout.setVisibility(View.GONE);
        }
    });

    listPopupWindow = new ListPopupWindow(context);
    listPopupWindow2 = new ListPopupWindow(context);
    viewHolder.imageButton.setOnTouchListener((v, event) -> {
        listPopupWindow.dismiss();
        View parentRow = (View) v.getParent();
        ListView listView = (ListView) parentRow.getParent();
        index = listView.getPositionForView(parentRow);
        showListPopupWindow(v);
        return false;
    });
    viewHolder.imageButton.setOnClickListener(v -> {
        View parentRow = (View) v.getParent();
        ListView listView = (ListView) parentRow.getParent();
        index = listView.getPositionForView(parentRow);
        if(L)Log.d("fileBrowser", "Index (Imagebutton): " + index);

        listPopupWindow.dismiss();
        showListPopupWindow(v);
    });

    return view;
}

Viewholder steht weiter unten:

private static class ViewHolder {
    public ImageButton checkedImage;
    public ImageButton imageButton;
    public TextView textView;
    public ConstraintLayout constraintLayout;
}

private ViewHolder createViewHolder(View v){
    ViewHolder holder = new ViewHolder();
    holder.checkedImage = v.findViewById(R.id.checkedImage);
    holder.imageButton = v.findViewById(R.id.btnListPopupWindow);
    holder.textView = v.findViewById(R.id.file_text);
    holder.constraintLayout = v.findViewById(R.id.listview_row_layout);
    return holder;
}

Habe ein kleines Update zu meinem Problem. Ich kann es mehr konkretisieren.
Durch mehrere Tests habe ich herausgefunden, dass es nicht zwingend in Reihe 1 und Reihe 11, sondern eher in Reihe Reihe 1 und dann in Reihe 13 ein Häkchen setzt. Reihe 13 ist dabei die zweite Reihe, die unter meinem Bildschirmrand liegt und auftaucht, wenn ich scrolle. Das ganze habe ich dann mit mehreren Versuchen durchgespielt und der Fehler tritt sogar manchmal so auf, dass am Ende nicht mal mehr Reihe 1 optisch ausgewählt ist, sondern mal Reihe 2, mal 3, oder 6. Es wechelt je nachdem wie schnell ich scrolle.

Bei Recherchen habe ich erfahren, dass es bei ScrollViews und ListViews häufiger zu Bugs kommt, die beim Recyclen der Reihen entstehen. Jetzt verstehe ich aber nicht worauf sich das bezieht.

Hoffentlich hat da jemand eine Idee oder zumindest einen Ansatz.

Grüße!

Alle möglichen Lösungsversuche führen dazu, dass man seine Views, die in einer Reihe dargestellt werden sollen, in einem Viewholder initialisiert und das genau da:

    View view = convertView;
    if(view == null){
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.fragment_file_browser_row, null);
        viewHolder = createViewHolder(view);
        view.setTag(viewHolder);
    }else{
        viewHolder = (ViewHolder) view.getTag();
    }

Mein Problem ist wahrscheinlich, dass ich den ImageButton checkedImage immer zusätzlich außerhalb des Viewholders initialisierte (viewHolder.checkedImage = v.findViewById(R.id.checkedImage)), damit ich das Bild des Buttons ändern kann.

Gibt es da eine andere Möglichkeit das umzusetzen? Es gibt ja auch die Methode Checkable, die ich nicht verstanden habe, weil sie schon mal nicht funktioniert hatte.

Wenn ich es richtig verstehe, müsste alles in der If Abfrage stattfinden wo der Viewholder instantiert werden. Das geht aber auch nicht.