Question

There is an really weird thing happening with my listview. I am creating an ListView with buttons and an editText.

It's disposed like this: [Button] [EditText] [Button], The buttons works like an "incrementer" and "decrementer" updating the numerical value of EditText in 1 unit per click. The problem is, when I click in an button, almost every time an editText of another list view element is changed (the editText of the clicked item is also changed). And if I click in a button of this erroneous changed item, it also changes the editText of the first one. They basically have the same reference of buttons and editText, although they have textViews with data, and this data is different between they.

To accomplish that I created and custom adapter:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if(convertView == null) {
            convertView = mInflater.inflate(R.layout.lastproduct_row, null);
            holder = new ViewHolder();
            holder.btnAddQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_add_qtd);
            holder.btnSubQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_sub_qtd);
            holder.etQuantidade = (EditText) convertView.findViewById(R.lastproduct_row.et_quantidade);                

            TextView tv;

            holder.tvList = new TextView[PRODUCTROW_INT_KEY.length];

            for(int i = 0; i < PRODUCTROW_INT_KEY.length; i++) {
                tv = (TextView) convertView.findViewById(PRODUCTROW_INT_KEY[i]);
                holder.tvList[i] = tv;                  
            }

            convertView.setTag(holder);
        }
        else {
            holder = (ViewHolder) convertView.getTag();
        }

        HashMap<String, String> hm = productsList.get(position);
        String key = hm.get(CODIGO_KEY);

        for(int i = 0; i < PRODUCTROW_INT_KEY.length; i++) {
            holder.tvList[i].setText(hm.get(PRODUCTROW_STR_KEY[i]));
        }

        holder.btnAddQtd.setTag(key+QTD_FLAG+ADD_ACTION);
        holder.btnSubQtd.setTag(key+QTD_FLAG+SUB_ACTION);
        holder.btnAddQtd.setOnClickListener(handle);
        holder.btnSubQtd.setOnClickListener(handle);

        if(novosEstoques.containsKey(key)) {
            holder.etQuantidade.setText(MyParseFunctions.parseCentesimal(novosEstoques.get(key).getQuantidade()));
        }

        return convertView;
    }

    class ViewHolder {
        private TextView []tvList;
        private Button btnAddQtd, btnSubQtd;
        private Button btnAddQtVol, btnSubQtVol;
        private EditText etQuantidade, etQtVolume;
    }

I added onClick listenners to the buttons, setting their tags with my listView element ID (concatenated with another informations). Then in my event listener I just get the button parent View (an LinearLayout) and get the EditText from that using getViewAt():

    @Override
    public void onClick(View v) {
        String tag = (String) v.getTag();

        if(tag.contains(QTD_FLAG)) {
            String []info = ((String) v.getTag()).split(QTD_FLAG);
            float qtd;
            LinearLayout ll = (LinearLayout) v.getParent();
            ll.setBackgroundColor(Color.rgb(0, 128, 30));
            EditText et = (EditText) ll.getChildAt(2);

            qtd = Float.parseFloat(et.getText().toString().replace(",", "."));

            if(info[1].equals(ADD_ACTION)) {
                qtd++;

            }
            else if(info[1].equals(SUB_ACTION)) {
                if(qtd > 0)
                    qtd--;
            }

            Log.d("TESTE", "MODIFICAR KEY = "+info[0]);
            et.setText(qtd+"");
        }           
    }

I'm using an setBackgroundColor in this example to confirm that the LinearLayout instance is duplicated in the lisView. When I click an Button, it's painted in 2 different list view item.

Anyone can point me what could be doing this? I have found people with an duplicated ListView item, I don know if that is my case, cause I have TextView's inside my ListView, and they are not equal, only the LinearLayout portion with buttons and editText is "shared".


I make some changes in my getView method and it's working now! It seems that every time the getView method is called i have not guarantee at all that my editTexts will be filled properly and I didn't realize that. So every getView call I make I set the editText value, if the user edit an ET value, I store it in a HashMap to restore in getView, if there is no entry in HashMap for the given editText, then I set it to the default value (zero):

    ...
    if(convertView == null) {
            holder = new ViewHolder();
            holder.btnAddQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_add_qtd);
            holder.btnSubQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_sub_qtd);
            holder.etQuantidade = (EditText) convertView.findViewById(R.lastproduct_row.et_quantidade); 

            //Now it is easier to get etQuantidade reference in button
            //click handle, I just have to do:
            //    public onClick(View v) {
            //        EditText etButtonAssociated = (EditText) v.getTag();
            //        ...
            //    }
            holder.btnAddQtd.setTag(holder.etQuantidade);
            holder.btnSubQtd.setTag(holder.etQuantidade);

            holder.btnAddQtd.setOnClickListener(handle);
            holder.btnSubQtd.setOnClickListener(handle);
            ...
    }
    else {
        ...
    }
    holder.etQuantidade.setTag(key);

    if(novosEstoques.containsKey(key)) {
        holder.etQuantidade.setText(MyParseFunctions.parseCentesimal(novosEstoques.get(key).getQuantidade()));
    }
    else {
        holder.etQuantidade.setText("0");
    }

    return convertView;
Was it helpful?

Solution

Israel,

After looking over your code, I was wondering about an implementation decision you have made. Since each Button is "bound" to a particular EditText, have you considered setting the Tag of those Buttons to the EditText? The Tag may be any Object including a UI element. This is especially useful for dynamic UI elements, such as a runtime populated list.

Since this is handled in your Adapter you wouldn't have to worry about duplicate Parents and such. Additionally, you could avoid having to worry about "finding" the control in your onClick() because you would have it (It's the tag). I'm not sure exactly what your project needs are, but this seems like a potentially viable solution, unless you need those Buttons to accomplish other tasks.

Note of Caution Just make sure that you erase the Tags' references to the EditText when you are done. Otherwise, you run the risk of leaking some memory.

FuzzicalLogic

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top