使用edittext和textwatcher的Listview。 Textwatcher多次触发(超过3次)

时间:2015-01-02 11:24:39

标签: android android-edittext textwatcher

我有一个自定义列表适配器,其中一个列表项有三个编辑文本。我有一个日期选择器。设置日期后,适配器的相应模型将正确保存日期。但对于其他编辑文本,我只想将输入的文本存储在列表中。我使用textwatcher来完成任务。我的问题是文本观察者为视图中的单个条目多次触发(准确地说是5次)。

如果其中一个编辑文本正常工作,为什么不能另一个?我真的可以使用一些帮助。到目前为止,我还没有找到任何成功。

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;

}

}

4 个答案:

答案 0 :(得分:7)

我知道我已经迟到了,但我会把它留给未来的读者。将textwatchers设置为listview项目由于它们的回收性质以及Textwatchers被添加到编辑文本而不被替换,这有点棘手。因此,您需要删除不正确的并在每次创建行视图或绑定到新数据时添加新的观察者。尝试以下实现:

1)自定义文本观察器。 (对象项是包含行数据的对象)

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)将textwatcher添加到您的edittext中,并在getView()函数中删除前一个。

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);

完成。您现在可以将文本保存在相应的行数据对象中。这样,当Textwatchers失去实用性并防止内存泄漏时,它们将被删除。

答案 1 :(得分:1)

由于编辑文本上的文本观察器,每次输入字符时都会调用观察者,并且每次都会撤销notifyDataSetChanged()。

例如:让我们说你要节省金额453,它会被解雇3次。

答案 2 :(得分:0)

我试图解决这个问题,因为我的问题之一 - 在列表视图时无法获得该位置 - &gt;编辑文本有一个文本观察者。

这是对我有用的解决方案:

在获取视图中 -

当我添加文本观察者监听器来编辑文本时,我还添加了以下行

edittext.setTag(R.id.position,position)

你的afterTextChanged中的

-  int position = edittext.getTag(R.id.position)

提供正确的位置编号,您可以根据位置编号进行修改。

答案 3 :(得分:0)

在 Kotlin 中,您可以使用以下扩展方法来解决这个问题。

fun EditText.onChange(cb: (str: String) -> Unit){
    this.removeWatcher()
    val watcher = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}

        override fun afterTextChanged(s: Editable?) {
            cb(s.toString())
        }
    }
    this.addTextChangedListener(watcher)
    this.tag = watcher
}

fun EditText.removeWatcher() {
    if(this.tag as TextWatcher? != null) {
        this.removeTextChangedListener(this.tag as TextWatcher)
    }
}

从适配器中使用它

yourEditText.onChange { str ->     // str is the new content
    // TODO: Implement listener here
}

每当您需要从 removeWatcher 中删除所有观察者时,都可以使用 EditText 方法。

例如:如果您使用 setText 从适配器在 EditText 中设置一些文本,则将调用已添加的观察者。在这种情况下,如果您在 setText 之前删除所有现有观察者,则可以避免不必要的观察者调用