今天做一个界面. 是 一个列表 .列表中有spinner,button,edittext等控件
首次打开需要展示,用户可以修改,修改后数据保存.
在保存Edittext控件上的值的时候,用的etRemark.addTextChangedListener(myTextWatcher)
注意是addTextChangedListener
来监听Edittext的值,如果变化的话 就将变化的值直接存入数据集对象中.
这样存在了几个问题
1,我们改变了一个editext的值后通过logcat 发现 onTextChanged会被多次调用.
我们知道listview在第一次展示的时候会多次调用getView方法来确定itemView的高度.
多次调用就会给同一个editext控件 add多个TextChangedListener.
public void addTextChangedListener(TextWatcher watcher) {
if (mListeners == null) {
mListeners = new ArrayList();
}
mListeners.add(watcher);
}
也就导致了为什么输入一次 会多次调用TextChangedListener的方法.
2,listview滑动后发现editext的值会混乱.
如果一屏为3个item
具体混乱特征为首次加载完listview的时候.
第一次滑动,滑倒第二页的时候第二屏的第一个(position=3)会把第一屏的第一个item(position=0)给覆盖掉.如果position=3的这个item为空的话.再滑到顶部则发现position的item 也为空了.
这个时候在position=0的item中的editext的值改变的时候,往下滑发现position=3的也改变了.
我们都知道这是convertView复用的结果.
具体原因是,在加载第二屏第一个的item的时候调用的getView()方法,
EditText et= ViewHolder.get(convertView, R.id.item_editText);
et.setText(datas.get(itemPosition).editTextValue);
et.addTextChangedListener(myTextWatcher);
我的代码里有一个settext(value)方法,,因为和第一屏的item用的是同一个editext对象
这个时候会触发TextChanged事件,因为用的是addTextChangedListener方法.所以这个editext中有多个listener
插入Textwatcher代码.
class MyTextWatcher implements TextWatcher{
private int position;
public MyTextWatcher(int position) {
super();
this.position = 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) {
datas.get(position).editTextValue= s.toString();
}
}
也会触发,所以这个时候,就会调用afterTextChanged()方法
因为我的TextWatcher对象中维护了一个position的全局变量,其实这个TextWatcher的position为0.则把position为3的edittext的值赋给了datas.get(0)editTextValue;所以存在了第一次滑动的时候会发现值会被覆盖的问题.
等到多次滑动后一个editext控件就会add多个TextWatcher对象,这个时候一旦修改一个editext的值,就会调用多个TextWatcher的textChanged回调,也就是为什么改一个position为0的editext.怎么也把position为3的editext也改了.
其实修改的是datas中的值.
怎么解决呢.看了半天废话终于到点子上了.
1 不复用converView,并且为listview的item指定高度阻止首次加载多次调用getView()方法.
但是这样每次都去inflate布局文件实在太坑了.
2 不用addTextChangedListener 改用 setOnFocusChangeListener() .靠失去焦点来触发保存数据
个人尝试过后没问题.但是失去焦点.总感觉有点不靠谱.不知道是不是web开发的后遗症,怕如果用户输入完后直接点击别的地方的按钮,会不会不会触发,(经过原生的android测试,发现无论是关闭输入框,还是点击别的地方的按钮,都会触发焦点丢失事件) 应该可以放心使用
3. 还用addTextChangedListener()来触发保存,不过在editext赋值之前先remov掉之前的TextWatcher
查看源码removeTextChangedListener()方法 用的是
public void removeTextChangedListener(TextWatcher watcher) {
if (mListeners != null) {
int i = mListeners.indexOf(watcher);
if (i >= 0) {
mListeners.remove(i);
}
}
}
list的indexOf()方法.
则需要重写TextWatcher的 equals()方法.
见代码
MyTextWatcher myTextWatcher = new MyTextWatcher(itemPosition);
et.removeTextChangedListener(myTextWatcher);
et.setText(datas.get(itemPosition).editTextValue);
et.addTextChangedListener(myTextWatcher);
MyTextWatcher类中重写
@Override
public boolean equals(Object o) {
return true;
}
这样就可以完美解决了;