天天看點

Android 實作多個EditText互相監聽遇到的問題及解決方法

上周在實作一個功能的時候遇到了很多問題,然後折騰了好久才解決,以防今後又遇上同樣的問題特在此記錄下。

我實作的功能要求是一個界面上有四個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.

繼續閱讀