Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listview with edittext and textwatcher. Textwatcher fires multiple times (more than 3 times)

I have a custom list adapter with one list item having three edit texts. And I Have a date picker for one of them. When a date is set, the corressponding model for the adapter is saved with the date correctly. But for the other edit texts, i just want the entered text to be stored in the list. And I use textwatcher to accomplish the task. My problem is the text watcher fires multiple times (5 times to be exact) for a single entry in the view.

If one of the edit texts works correctly, why not the other? I could really use some help. I've been unable to find any success so far.

public class AddExpensesAdapter extends BaseAdapter{
private Activity activity;
private ArrayList<AddExpensesModel> addExpensesList;
private LayoutInflater inflater;
private  TextView totalAmount;
private ArrayList<String> array_amount= new ArrayList<String>();
private ArrayList<String> array_name= new ArrayList<String>();
public AddExpensesAdapter(Activity activity, ArrayList<AddExpensesModel> addExpensesList)        {
    this.activity = activity;
    this.addExpensesList = addExpensesList;
    this.inflater = (LayoutInflater) this.activity
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

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

@Override
public Object getItem(int position) {
    return null;
}

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

public AddExpensesModel getExpenseModel(int position)
{
    return addExpensesList.get(position);
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;
    if (convertView == null) {
        viewHolder = new ViewHolder();
        convertView = inflater.inflate(R.layout.a_add_expenses_listitem, null);


        viewHolder.expenseName = (EditText) convertView.findViewById(R.id.add_expenses_et_expense_name);
        viewHolder.dateTime = (EditText) convertView.findViewById(R.id.add_expenses_et_date_time);
        viewHolder.amount = (EditText) convertView.findViewById(R.id.add_expenses_et_amount);
        viewHolder.editDate = (ImageView) convertView.findViewById(R.id.add_expenses_edit_date);
        viewHolder.number = (TextView) convertView.findViewById(R.id.add_expenses_tv_serial_number);
        viewHolder.deleteExpense = (ImageView) convertView.findViewById(R.id.add_expenses_delete_expense);
        // viewHolder.totalfriends = (TextView)
        // convertView.findViewById(R.id.eventtotalfriends);

        convertView.setTag(viewHolder);
        viewHolder.ref = position;
    } else {
        viewHolder = (ViewHolder) convertView.getTag();

    }


    final AddExpensesModel addExpenseModel = addExpensesList.get(position);

    viewHolder.expenseName.setText(addExpenseModel.getExpenseName());
    viewHolder.dateTime.setText(addExpenseModel.getDateTime());
    viewHolder.amount.setText(addExpenseModel.getAmount());
    viewHolder.number.setText(""+(position+1)+".");




    viewHolder.editDate.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            try {
                setDate(addExpenseModel);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

    viewHolder.deleteExpense.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            addExpensesList.remove(position);
            notifyDataSetChanged();
        }
    });


        viewHolder.amount.addTextChangedListener(new TextWatcher() {

            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {

            }

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

            }

            @Override
            public void afterTextChanged(Editable editable) {

                if(!editable.toString().equals(""))
                {


                                addExpenseModel.setAmount(editable.toString());

                        }


                    notifyDataSetChanged();

            }
        });

    return convertView;
}



public void setDate(final AddExpensesModel model) throws Exception {

    final String dateFormatPattern = "MMM, dd yyyy";
    final SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern,
            Locale.getDefault());

    DatePickerDialog.OnDateSetListener date = new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker view, int year, int monthOfYear,
                              int dayOfMonth) {
            Calendar cal = Calendar.getInstance();
            cal.set(Calendar.YEAR, year);
            cal.set(Calendar.MONTH, monthOfYear);
            cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
            model.setDateTime(sdf.format(cal.getTime()));
            notifyDataSetChanged();
        }
    };

    Calendar cal = Calendar.getInstance();
    cal.setTime(sdf.parse(model.getDateTime()));
    new DatePickerDialog(this.activity, date, cal.get(Calendar.YEAR),
            cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)).show();
}

static class ViewHolder {
    EditText expenseName;
    EditText dateTime;
    EditText amount;
    ImageView editDate;
    ImageView deleteExpense;
    TextView number;

}

}

like image 891
Robin Rex Avatar asked Jan 09 '23 04:01

Robin Rex


1 Answers

I know I'm late, but I'll leave this here for future readers. It's a bit tricky to set textwatchers to listview items due to their recycling nature and also since Textwatchers are added to an edit text and not replaced. So you need to remove the incorrect ones and add new watchers every time a row view is created or bound to new data. Try the following implementation:

  1. The custom text watcher. (Object item is the object that contains your row data)

    private class CustomWatcher implements TextWatcher { private Object item;

     private CustomWatcher(Object item)
     {
         this.item = item;
     }
    
     @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)
     {
    
     }
    

    }

  2. Add the textwatcher to your edittext and remove the previous one, inside your getView() function.

    CustomWatcher oldWatcher = (CustomWatcher)holder.editDate.getTag(); if(oldWatcher != null) holder.editDate.removeTextChangedListener(oldWatcher);

    //populate your editText with the model data here (before adding the new text watcher)

    CustomWatcher newWatcher = new CustomWatcher(rowItem); holder.editDate.setTag(newWatcher); holder.editDate.addTextChangedListener(newWatcher);

Done. You can now save the text in the corresponding row data object. This way, your Textwatchers will get removed when they have outlived their usefulness and prevent memory leaks as well.

like image 73
ravindu1024 Avatar answered Feb 14 '23 04:02

ravindu1024