淘先锋技术网

首页 1 2 3 4 5 6 7

今天做一个界面.  是 一个列表 .列表中有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;

}

这样就可以完美解决了;