重寫了EditText的setText()后報String cannot be cast to android.text.Editable錯誤


2019-08-13

關鍵字:自定義EditText、java.lang.ClassCastException: java.lang.String cannot be cast to android.text.Editable


 

錯誤發生在繼承自官方 EditText 實現自定義視圖的場景下。當重寫了父類中的 

public void setText(CharSequence text, BufferType type)

方法時就報了異常,異常堆棧信息如下:

08-13 02:34:31.342 5859-5859/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.my.pkg, PID: 5859
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.pkg/com.my.pkg.MainActivity}: android.view.InflateException: Binary XML file line #10: Error inflating class com.my.pkg.IPEditText
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
     Caused by: android.view.InflateException: Binary XML file line #10: Error inflating class com.my.pkg.IPEditText
        at android.view.LayoutInflater.createView(LayoutInflater.java:621)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:697)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:756)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
        at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
        at android.app.Activity.setContentView(Activity.java:1929)
        at com.my.pkg.MainActivity.onCreate(MainActivity.java:21)
        at android.app.Activity.performCreate(Activity.java:5231)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
        at android.app.ActivityThread.access$800(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.constructNative(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at android.view.LayoutInflater.createView(LayoutInflater.java:595)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:697) 
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:756) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:492) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:353) 
        at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290) 
        at android.app.Activity.setContentView(Activity.java:1929) 
        at com.my.pkg.MainActivity.onCreate(MainActivity.java:21) 
        at android.app.Activity.performCreate(Activity.java:5231) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
        at android.app.ActivityThread.access$800(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
     Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to android.text.Editable
        at android.widget.EditText.getText(EditText.java:75)
        at com.my.pkg.IPEditText.textInitialization(IPEditText.java:55)
        at com.my.pkg.IPEditText.<init>(IPEditText.java:43)
        at java.lang.reflect.Constructor.constructNative(Native Method) 
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423) 
        at android.view.LayoutInflater.createView(LayoutInflater.java:595) 
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:697) 
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:756) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:492) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:353) 
        at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290) 
        at android.app.Activity.setContentView(Activity.java:1929) 
        at com.my.pkg.MainActivity.onCreate(MainActivity.java:21) 
        at android.app.Activity.performCreate(Activity.java:5231) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
        at android.app.ActivityThread.access$800(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 

這份異常的關鍵在於最后標紅加粗部分。它描述的是遇到了類型轉換異常,String 不能被強轉成 Editable。

 

到底怎么回事呢?

 

原因是在重寫了父類的 setText(CharSequence, BufferType) 后沒有調用父類中的這個方法,即:

    @Override
    public void setText(CharSequence text, BufferType type) {
//        super.setText(text, type);
    }

 

那為什么不執行父類的這個方法,竟然會導致類型轉換異常呢?

 

這個得去跟蹤一下 TextView 的源碼,即 EditText 的父類,EditText 雖然繼承自 TextView,但它並沒有多少自己的邏輯,主要還是靠 TextView。

 

在 TextView 中,用於記錄顯示的文本的是 mText 變量。

private CharSequence mText;

這個變量的值默認是 null,在構造方法中被指向一個空的 String 常量:

在 TextView 的構造方法中,會去讀取 xml 中配置在 android:text 屬性中的字符串值:

隨后會調用 setText 方法來為 mText 賦值,將 xml 中的文本值賦給 mText 變量。

前面的 text 變量本身就是 CharSequence 類型的,默認的 setText 方法里面也並沒有什么什么特別的操作,就是簡單地將 text 的值賦給了 mText 而已,但是在這里有一個很重要的性質的改變,就是原本的指向普通空值 String 的 mText 在經過了 setText 以后變成了指向一個 CharSequence 類型對象。

 

這一性質轉換本身並不會引發什么,但是 EditText 的加載過程中會去調用 getText() 方法。EditText 方法中的 getText() 方法的實現很短,如下所示:

    @Override
    public Editable getText() {
        return (Editable) super.getText();
    }

它會去向父類,即 TextView,通過 getText() 方法要來值,再不由分說強轉成 Editable 返回。TextView 中的 getText() 的實現是什么?就是簡單的將 mText 對象返回嘛:

    public CharSequence getText() {
        return mText;
    }

到這,就足夠清晰了吧?

 

如果沒有執行父類的 setText(CharSequence,BufferType) 方法,那么,mText 就默認指向一個空值 String 類對象。在 EditText 的加載過程中會去調用 getText() 方法,這樣一來,就要強制將 String 類型轉換成 Editable 類型了,這種轉換是不正確的。

 

那怎么解決呢?我就是不想調用父類的 setText(CharSequence,BufferType) 方法,能避免這個錯誤嗎?

 

我不知道啊。mText 是 private 修飾的,不能直接更改。但是感覺可以嘗試一下用反射的方式來解決,給 mText 一個正兒八經的 CharSequence 類對象就可以了嘛。如果你實在有興趣,可以仔細去研讀一下 TextView 的源碼以尋求一個解決方案了,我反正是沒興趣。

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM