问题
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;
}
}
回答1:
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 everytime 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.
回答2:
It's because of Text Watcher on your Edit Text, each time when you entered character text watcher will be called and each time your notifyDataSetChanged() will be revoked.
For example: let's say you want to save amount 453, it will be fired 3 times.
回答3:
I was trying to fix this for one of my problem - not able to get the position when list view -> edit text has a text watcher.
This is the solution that worked for me :
In get view -
when I am add text watcher listener to edit text, I also added the below line
edittext.setTag(R.id.position, position)
in your afterTextChanged - int position = edittext.getTag(R.id.position)
Gives the correct position number and you can do modifications based on the position number.
来源:https://stackoverflow.com/questions/27741390/listview-with-edittext-and-textwatcher-textwatcher-fires-multiple-times-more-t