上周在實作一個功能的時候遇到了很多問題,然後折騰了好久才解決,以防今後又遇上同樣的問題特在此記錄下。
我實作的功能要求是一個界面上有四個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.