Android編程開發中類型轉化錯誤怎麼辦?

Android編程開發中類型轉化錯誤怎麼辦?今天遇到一bug,報錯如下

09-15 11:07:29.075  7669  7669 E AndroidRuntime: FATAL EXCEPTION: main
09-15 11:07:29.075  7669  7669 E AndroidRuntime: Process: com.android.mms, PID: 7669
09-15 11:07:29.075  7669  7669 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.mms/com.android.mms.ui.ComposeMessageActivity}: java.lang.ClassCastException: android.widget.TextView cannot be cast to com.android.mms.ui.MyMarqueeTextView
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2743)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2808)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4657)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread.-wrap19(ActivityThread.java)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1550)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:110)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:203)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:6293)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1086)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
09-15 11:07:29.075  7669  7669 E AndroidRuntime: Caused by: java.lang.ClassCastException: android.widget.TextView cannot be cast to com.android.mms.ui.MyMarqueeTextView
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at com.android.mms.ui.ComposeMessageActivity.updateTitle(ComposeMessageActivity.java:2727)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at com.android.mms.ui.ComposeMessageActivity.initialize(ComposeMessageActivity.java:3400)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at com.android.mms.ui.ComposeMessageActivity.onCreate(ComposeMessageActivity.java:3086)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.Activity.performCreate(Activity.java:6681)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2696)
09-15 11:07:29.075  7669  7669 E AndroidRuntime:    ... 10 more

可能情況1 java代碼中向下轉型錯誤

比如如下栗子
xml:

    

    

主界面

public class MainActivity extends Activity {
    TextView tv = null;
    TextView auto = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        tv.setTextColor(Color.BLUE);

        auto = (AutoMarqueeTextView) findViewById(R.id.auto);
        auto.setTextColor(Color.RED);

        auto = (AutoMarqueeTextView)tv;//向下轉型報錯
    }
}

PS:AutoMarqueeTextView是繼承TextView的子類
雖然說父類引用可以指向子類對象,即所謂的向上轉型(子類轉父類)
即:

TextView auto = null;
auto = (AutoMarqueeTextView) findViewById(R.id.auto);

但是向下轉型是有問題的,tv是TextView(父類),不能轉換為子類AutoMarqueeTextView,這也是為什麼

auto = (AutoMarqueeTextView)tv;//編譯無錯誤,運行時將出錯 

會報錯。核心報錯在於(AutoMarqueeTextView)tv;,而報錯類型正是ClassCastException

換句話說,父類可以指向子類對象,但是卻不能將父類強制轉化為子類

但是有一個情況例外
比如B extends A
那麼如下代碼是沒有問題的:

 A a = new B();
 B b = (B)a;

以上代碼縮寫的話就是

B b = (B)new B();

原因是a本來就是B對象的實例
以上這種沒有錯誤的寫法用在android的栗子中,就是

    TextView tv = null;
    AutoMarqueeTextView auto = null;
    tv = (AutoMarqueeTextView) findViewById(R.id.auto);
        auto = (AutoMarqueeTextView)tv;

為避免向下轉型問題發生可以加入如下判斷

        TextView tv = null;
        AutoMarqueeTextView auto = null;
        tv = (AutoMarqueeTextView) findViewById(R.id.auto);
        if(tv instanceof AutoMarqueeTextView){
            Log.v("chj","tv is AutoMarqueeTextView");
            auto = (AutoMarqueeTextView)tv;
        }else{
            Log.v("chj","tv is not AutoMarqueeTextView");
        }

最終應該會打印
03-08 13:12:39.317 5807 5807 V chj : tv is AutoMarqueeTextView

可能情況2 xml中的定義與java代碼中的不匹配(xml引起的類型轉化錯誤)

比如xml定義為:

    

而java代碼卻是這樣:

AutoMarqueeTextView auto = null;
auto = (AutoMarqueeTextView) findViewById(R.id.auto);

就會報錯。其實本質原因一樣。findViewById(R.id.auto);取到的是TextView(父類),強制轉換成子類或者說向下轉型時報錯。

今天遇到的問題是android 7.1加入的分屏功能引起的。
分屏和全屏時使用的xml不一樣,之前隻修改瞭一個xml和java文件,導致在分屏時java與另一個xml不匹配,發生瞭類型轉化錯誤。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *