上周在实现一个功能的时候遇到了很多问题,然后折腾了好久才解决,以防今后又遇上同样的问题特在此记录下。
我实现的功能要求是一个界面上有四个EditText控件,其中任意一个内容变化,其他三个都要根据算法做出相应变化,这就牵扯到了多个EditText相互监听的问题了。
要实现EditText的监听就会用到TextWatcher;
首先我们来了解一下TextWatcher的用法吧!
功能:
1.监听EditText里输入内容的变化;
2.根据实时输入的文字内容,做出输入自动提示效果
TextWatcher myWatcher = newTextWatcher(){
@Override
public void onTextChanged(CharSequence s,int start,int before,int count){
System.out.println("onTextChanged");
System.out.println("s = "+s+",start = "+start+",before = "+before+",count = "+count);
}
@Override
public void beforeTextChanged(CharSequence s,int start,int count,int after){
System.out.println("beforeTextChanged");
System.out.println("s = "+s+",start = "+start+",count = "+count+",after = "+after);
}
@Override
public void afterTextChanged(Editable s){
System.out.println("afterTextChanged");
System.out.println("s = " + s);
}
};
大家可以根据各参数打印出来的结果了解参数具体指什么;
触发过程:
1.beforeTextChanged(CharSequence s,int start,int count,int after);
在EditText里的内容即将发生变化之前触发,EditText里的内容变化有3种方式:
1.新增加字符;2.删除字符;3.替换输入框中的若干个字符。
该方法反映的是,EditText在要发生变化之前,原来的内容字符串s有哪几个字符将要发生何种变化。
无论何种变化方式,都可以理解为:输入框的原内容字符串s,从索引位置start开始,
有count个字符即将被替换, 替换这count个字符的新的字符个数为after
注意:s是变化之前的输入框内容
2.onTextChanged(CharSequence s,int start,int before,int count);
在EditText里的内容发生变化之时触发,
在变化时的新的字符串s里,从索引位置start开始,有count个字符,是替换了原来的before个字符的
注意:s是变化之后的输入框内容
3.afterTextChanged(Editable s)
text变化之后触发,s是最终新的输入框内容
问题一:
接下来当我最初开始使用edittext的TextWatcher,运行程序时出现了java.lang.StackOverflowError错误,
经过分析知道,每次使用setText()方法为EditText添加数据时,会重新触发监听器,并不断的进行递归,造成死循环,最后程序崩溃。
针对这个,我试了两种解决方案:
1. 设置一个flag, 例:
private boolean autochange = false;
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(autochange) { // skip execution if triggered by code
autochange=false; // next change is not triggered by code
return;
}
if (s.length() != 0) {
switch (et.getId()) {
case R.id.etUsername: {
}
break;
case R.id.etPassword: {
phone = formatPhoneNumber(phone);
Log.i("PHONE", "Phone NUMB IS:"+phone);
autochange=true;
mPassword.setText(phone);
}
}
}
}
2. 每次设置文本的时候移除原来的监听,然后再重置一个监听:
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//Toast.makeText(getApplicationContext(), "In onTextChanged() Method", Toast.LENGTH_SHORT).show();
if (s.length() != 0) {
switch (et.getId()) {
case R.id.etUsername: {
}
break;
case R.id.etPassword: {
mPassword.removeTextChangedListener(theWatcher);
phone = formatPhoneNumber(phone);
Log.i("PHONE", "Phone NUMB IS:"+phone);
mPassword.setText(phone); //THE ERROR HAPPENS HERE
mPassword.addTextChangedListener(theWatcher);
}
}
}
}
问题二:
错误:android.content.res.Resources$NotFoundException
原因:一般发生在参数 int resId 错误,你把String赋值给int的resId,所以编译器找不到正确的resource于是报错。
检查一下edittext.setText之类的函数,这种函数通常有几个重载,如:
editText.setText(CharSequence text);
editText.setText(int resId);
......
如果不小心将一个int值传给了它,那它不会显示该int值,而是跑到工程下去找一个对应的resource的id,当然是找不到的,于是就报错啦。
解决办法是使用String.valueOf,例:
count.setText(String.valueOf(incall.getCount()));
问题三:
多个EditText相互监听死循环:可以在每个EditText聚焦时再监听其文本变化,即先给edittext设置setOnTouchListener, 然后在此下面进行TextWatcher.