Anish Hirlekar
Anish Hirlekar

Reputation: 233

EditText TextChangedListener inside Custom ArrayAdapter does not give correct position of list item. The value of position returned is always 0.

I have a custom ArrayAdapter implementation as follows:

private final LayoutInflater inflater;
private final Context mContext;
private final int resource;
private ListObject item;

public CheckListAdapter(Context cx, int res, List<ListObject> list){
    super(cx,res,list);
    resource=res;
    mContext=cx;
    inflater=LayoutInflater.from(cx);
}

@Override
public View getView(int position, View convertView, ViewGroup container) {
    convertView = (LinearLayout) inflater.inflate(resource, null);

    item = getItem(position);

    TextView slotNoView = (TextView)convertView.findViewById(R.id.itemSlotNo);
    TextView itemNameView = (TextView)convertView.findViewById(R.id.itemnameview);
    TextView itemIdView = (TextView)convertView.findViewById(R.id.itemIdView);

    String slotNo = item.getSlotNo();
    String itemName = item.getItemName();

    slotNoView.setText(slotNo+".");
    itemNameView.setText(itemName);
    itemIdView.setText(item.getId());

    EditText value = (EditText)convertView.findViewById(R.id.value);
    value.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) {
            String new6amVal = value.getText().toString();

            Log.d("ListView Position",Integer.toString(position));

            Log.d("Item ID: ",item.getId());
            Log.d("Item value: ",value.getText().tostring());
        }
    });


    return convertView;
}

All the TextViews get correctly populated when the adapter is created and sent to the list view. But when I make change in the EditText of any of the list item, the change is reflected only in the first list item EditText. When I log the position variable obtained in the getView method from inside the TextChangeListener, I can see that the value of position is always 0. How can I obtain the correct value of position of each list item from inside the getView method?

I also tried to check the value of position by using the OnFocusChangeListener but the value returned is always of the first position.

Upvotes: 1

Views: 610

Answers (1)

Joey Dalu
Joey Dalu

Reputation: 1113

You should use the recommended ViewHolder pattern for your adapter, and set your position as final. If that doesn't work then I suggest you create a custom TextWatcher class which keeps track of the position itself. Here's some sample code.

For ViewHolder pattern, create a class that extends RecyclerView.ViewHolder and find all your views there

 public class MyViewHolder extends RecyclerView.ViewHolder {

    TextView slotNoView;
    TextView itemNameView;
    TextView itemIdView;
    EditText value;

    public MyViewHolder(View itemView) {
        super(itemView);
        slotNoView = (TextView) itemView.findViewById(R.id.itemSlotNo);
        itemNameView = (TextView)itemView.findViewById(R.id.itemnameview);
        itemIdView = (TextView) itemView.findViewById(R.id.itemIdView);
        value = (EditText) itemView.findViewById(R.id.value);
    }
}

Then in your getView adapter method, create a new instance of the ViewHolder only if your convertview is null. Like this (remember to make position final)

@Override
public View getView(final int position, View convertView, ViewGroup container) {
    MyViewHolder viewHolder;
    if(convertView == null){
        convertView =  inflater.inflate(resource, container, false);

    }
    viewHolder = new MyViewHolder(convertView);

    item = getItem(position);
    String slotNo = item.getSlotNo();
    String itemName = item.getItemName();
    viewHolder.slotNoView.setText(slotNo+".");
    viewHolder.itemNameView.setText(itemName);
    viewHolder.itemIdView.setText(item.getId());

    viewHolder.value.addTextChangedListener(new TextWatcher() {
        //implement your stuff
        ...
    }

}

If that doesn't work, create a custom abstract class that implements TextWatcher which would be aware of the position and then just implement a method getPosition() in it to give you the position when you need it. You can pass the position in constructor. Example:

private abstract class PositionAwareTextWatcher implements TextWatcher{

    private int position;

    public PositionAwareTextWatcher(int position){
        this.position = position;
    }

    public int getPosition(){
        return this.position;
    }

}

Then in your getView where your setting the TextWatcher, use it like this then

viewHolder.value.addTextChangedListener(new PositionAwareTextWatcher(position) {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            String new6amVal = value.getText().toString();

            Log.d("ListView Position",Integer.toString(getPosition()));

            Log.d("Item ID: ",item.getId());
        Log.d("Item value: ",value.getText().tostring());
        }
    };

Upvotes: 2

Related Questions