user7466895
user7466895

Reputation: 319

Android ListView with EditText values duplicating with TextWatcher

I have a ViewHolder:

import android.widget.EditText;
import android.widget.TextView;

public class ListViewHolder {
    TextView productName;
    EditText productStock;
}

And my ListAdapter (listProducts is an ArrayList of Product objects):

public Product getItem(int position){
    return listProducts.get(position);
}


public View getView(final int position, View convertView, ViewGroup parent){
    View row;
    final ListViewHolder listViewHolder;

    if(convertView == null){
        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = layoutInflater.inflate(R.layout.set_stock_listview,parent,false);
        listViewHolder = new ListViewHolder();
        listViewHolder.productName = (TextView) row.findViewById(R.id.productName);
        listViewHolder.productStock = (EditText) row.findViewById(R.id.productStock);
        row.setTag(listViewHolder);
    }
    else{
        row = convertView;
        listViewHolder = (ListViewHolder) row.getTag();
    }

    final Product product = getItem(position);

    if(product.getDesiredQuantity()>0){
        listViewHolder.productStock.setText(String.valueOf(product.getDesiredQuantity()));
    }

    listViewHolder.productName.setText(product.getName()+":");
    listViewHolder.productStock.setInputType(InputType.TYPE_CLASS_NUMBER);
    listViewHolder.productStock.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        @Override
        public void afterTextChanged(Editable editable) {
            product.setDesiredQuantity(Integer.valueOf(editable.toString()));
        }
    });
    return row;
}

However when scrolling through the list, the value of the EditText duplicates to many of the other rows. It looks like it must be updating the other Product objects also but I haven't been able to find the issue, any ideas?

Upvotes: 1

Views: 239

Answers (1)

Ben P.
Ben P.

Reputation: 54204

The problem is a combination of the fact that views can be recycled (via the convertView argument) and the fact that TextView only allows you to add a TextWatcher. In the code you've posted, every time getView() is called with a non-null convertView, you will create an additional TextWatcher and assign it to productStock... and the previous watchers will remain in place updating the previously-bound product.

You have to remove the existing TextWatcher if it has one. I recommend using the ListViewHolder to accomplish this.

public class ListViewHolder {
    TextView productName;
    EditText productStock;
    TextWatcher productStockWatcher;
}

And then change this:

listViewHolder.productStock.addTextChangedListener(new TextWatcher() { ... });

To this:

if (listViewHolder.productStockWatcher != null) {
    listViewHolder.productStock.removeTextChangedListener(productStockWatcher);
}

listViewHolder.productStockWatcher = new TextWatcher() { ... };
listViewHolder.productStock.addTextChangedListener(listViewHolder.productStockWatcher);

Upvotes: 2

Related Questions