• 重写了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 的源码以寻求一个解决方案了,我反正是没兴趣。


  • 相关阅读:
    GUI的最终选择Tkinter模块初级篇
    JavaScript的进阶篇
    html标签详解
    docker使用自定义镜像zabbix服务
    Django之url定义和ORM框架的使用
    zabbix实现企业微信监控报警
    centos6 搭建nginx实现负载均衡
    mysql数据库进阶篇
    Linux运维之Ansible自动化运维管理工具
    php菜刀分析学习
  • 原文地址:https://www.cnblogs.com/chorm590/p/11337897.html
Copyright © 2020-2023  润新知