(Dynamic layout) Button listener in my view update multiple textview instead of 1

Tags: ,



I’m trying android for 2 weeks and I run into some problem. I have a list of burger that I fetch from my database, I made a view with that. The app needs to increment and decrement the quantity that the user wants so that he can pass an order. enter image description here My problem is that when I click on the + button, the app update multiple text view and I don’t understand where that came from and how to fix it.

here is a sample of my code for the view :

package com.example.fastfood;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;

public class BurgerAdapter extends ArrayAdapter<Burger> {
    public BurgerAdapter(Context context, ArrayList<Burger> burgers) {
        super(context, 0,burgers);
    }

    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        final Burger burger = getItem(position);
        if(convertView == null){
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_burger, parent, false);
        }
        TextView burgerName = (TextView) convertView.findViewById(R.id.burgerName);
        TextView burgerPrice = (TextView) convertView.findViewById(R.id.burgerPrice);
        TextView qteCmd = (TextView) convertView.findViewById(R.id.qteCmd);
        Button btnMoins = (Button) convertView.findViewById(R.id.moins);
        Button btnPlus = (Button) convertView.findViewById(R.id.plus);
        btnMoins.setTag(qteCmd);
        btnPlus.setTag(qteCmd);
        btnMoins.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView qteCmd = (TextView) v.getTag();
                burger.changeQuantitee(-1);
                Log.d("DEBUG", "Button moins : "+burger.getNom()+" "+burger.getQuantitee()+" "+qteCmd.getId());
                qteCmd.setText(Integer.toString(burger.getQuantitee()));
            }
        });

        btnPlus.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView qteCmd = (TextView) v.getTag();
                burger.changeQuantitee(1);
                Log.d("DEBUG", "Button moins : "+burger.getNom()+" "+burger.getQuantitee()+" "+qteCmd.getId());
                qteCmd.setText(Integer.toString(burger.getQuantitee()));
            }
        });
        burgerName.setText(burger.getNom());
        burgerPrice.setText(burger.getPrix()+"€");
        return convertView;
    }
}

Answer

You are not supposed to alter views of an AdapterView (ListView, Spinner, RecyclerView etc) inside methods that do not belong to Adapter classes (as you do with your onClick() method overrides. What you should be doing is after you mutate your data model notify the Adapter with .notifyDataSetChanged().

Also I strongly suggest that you do not capture the local variable Burger inside the onClick(). Rather, fetch the data from burgersList with adapter position. So your code be like:

 btnMoins.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView qteCmd = (TextView) v.getTag();
                Burger b = getItem(position);
                b.changeQuantitee(-1);
                Log.d("DEBUG", "Button moins : "+burger.getNom()+" "+burger.getQuantitee()+" "+qteCmd.getId());

               //Instead of changing the state of the TextView yourself, you should instead do following:
                BurgerAdapter.this.notifyDataSetChanged();
            }
        });


Source: stackoverflow