调用自定义 Button 类的构造函数时出现 ClassCastException

Posted

技术标签:

【中文标题】调用自定义 Button 类的构造函数时出现 ClassCastException【英文标题】:ClassCastException when calling constructor for custom Button class 【发布时间】:2015-11-18 03:15:12 【问题描述】:

我正在使用一些简单的 android 应用程序代码,但存在与代码中所有布局相关的问题。

当我在 Eclipse 中打开布局时出现此错误

The following classes could not be instantiated:
- com.android2.calculator3.view.ColorButton (Open Class, Show Error Log)
See the Error Log (Window > Show View) for more details.
Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse

java.lang.ClassCastException: com.android.layoutlib.bridge.android.BridgeContext cannot be cast to com.android2.calculator3.Calculator
at com.android2.calculator3.view.ColorButton.<init>(ColorButton.java:39)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(    at sun.reflect.NativeConstructorAccessorImpl.newInstance(    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(    at java.lang.reflect.Constructor.newInstance(    at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:442)
at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:194)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:132)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:806)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:385)

这是我在 Colorbutton.java 中的代码

 package com.android2.calculator3.view;

 import java.util.regex.Pattern;

 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.widget.Button;

 import com.android2.calculator3.Calculator;
 import com.android2.calculator3.EventListener;
 import calculator.app.R;

 /**
 * Button with click-animation effect.
 */
class ColorButton extends Button 
int CLICK_FEEDBACK_COLOR;
static final int CLICK_FEEDBACK_INTERVAL = 10;
static final int CLICK_FEEDBACK_DURATION = 350;

float mTextX;
float mTextY;
long mAnimStart;
EventListener mListener;
Paint mFeedbackPaint;
Paint mHintPaint = new Paint();
Rect bounds = new Rect();
float mTextSize = 0f;

public ColorButton(Context context, AttributeSet attrs) 
    super(context, attrs);
    Calculator calc = (Calculator) context;
    init(calc);
    mListener = calc.mListener;
    setOnClickListener(mListener);
    setOnLongClickListener(mListener);


private void init(Calculator calc) 
    Resources res = getResources();

    CLICK_FEEDBACK_COLOR = res.getColor(R.color.magic_flame);
    mFeedbackPaint = new Paint();
    mFeedbackPaint.setStyle(Style.STROKE);
    mFeedbackPaint.setStrokeWidth(2);
    getPaint().setColor(res.getColor(R.color.button_text));
    mHintPaint.setColor(res.getColor(R.color.button_hint_text));

    mAnimStart = -1;


private void layoutText() 
    Paint paint = getPaint();
    if(mTextSize != 0f) paint.setTextSize(mTextSize);
    float textWidth = paint.measureText(getText().toString());
    float width = getWidth() - getPaddingLeft() - getPaddingRight();
    float textSize = getTextSize();
    if(textWidth > width) 
        paint.setTextSize(textSize * width / textWidth);
        mTextX = getPaddingLeft();
        mTextSize = textSize;
    
    else 
        mTextX = (getWidth() - textWidth) / 2;
    
    mTextY = (getHeight() - paint.ascent() - paint.descent()) / 2;
    if(mHintPaint != null) mHintPaint.setTextSize(paint.getTextSize() * 0.8f);


@Override
protected void onTextChanged(CharSequence text, int start, int before, int after) 
    layoutText();


@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) 
    super.onLayout(changed, left, top, right, bottom);
    if(changed) layoutText();


private void drawMagicFlame(int duration, Canvas canvas) 
    int alpha = 255 - 255 * duration / CLICK_FEEDBACK_DURATION;
    int color = CLICK_FEEDBACK_COLOR | (alpha << 24);

    mFeedbackPaint.setColor(color);
    canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, mFeedbackPaint);


@Override
public void onDraw(Canvas canvas) 
    if(mAnimStart != -1) 
        int animDuration = (int) (System.currentTimeMillis() - mAnimStart);

        if(animDuration >= CLICK_FEEDBACK_DURATION) 
            mAnimStart = -1;
        
        else 
            drawMagicFlame(animDuration, canvas);
            postInvalidateDelayed(CLICK_FEEDBACK_INTERVAL);
        
    
    else if(isPressed()) 
        drawMagicFlame(0, canvas);
    

    CharSequence hint = getHint();
    if(hint != null) 
        String[] exponents = hint.toString().split(Pattern.quote("^"));
        int offsetX = getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_offset_x);
        int offsetY = (int) ((mTextY + getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_offset_y) - getTextHeight(mHintPaint,
                hint.toString())) / 2)
                - getPaddingTop();

        float textWidth = mHintPaint.measureText(hint.toString());
        float width = getWidth() - getPaddingLeft() - getPaddingRight() - mTextX - offsetX;
        float textSize = mHintPaint.getTextSize();
        if(textWidth > width) 
            mHintPaint.setTextSize(textSize * width / textWidth);
        

        for(String str : exponents) 
            if(str == exponents[0]) 
                canvas.drawText(str, 0, str.length(), mTextX + offsetX, mTextY - offsetY, mHintPaint);
                offsetY += getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_exponent_jump);
                offsetX += mHintPaint.measureText(str);
            
            else 
                canvas.drawText(str, 0, str.length(), mTextX + offsetX, mTextY - offsetY, mHintPaint);
                offsetY += getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_exponent_jump);
                offsetX += mHintPaint.measureText(str);
            
        
    

    CharSequence text = getText();
    canvas.drawText(text, 0, text.length(), mTextX, mTextY, getPaint());


private int getTextHeight(Paint paint, String text) 
    mHintPaint.getTextBounds(text, 0, text.length(), bounds);
    int height = bounds.height();
    String[] exponents = text.split(Pattern.quote("^"));
    for(int i = 1; i < exponents.length; i++) 
        height += getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_exponent_jump);
    
    return height;


public void animateClickFeedback() 
    mAnimStart = System.currentTimeMillis();
    invalidate();


@Override
public boolean onTouchEvent(MotionEvent event) 
    boolean result = super.onTouchEvent(event);

    switch(event.getAction()) 
    case MotionEvent.ACTION_UP:
        if(isPressed()) 
            animateClickFeedback();
        
        else 
            invalidate();
        
        break;
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_CANCEL:
        mAnimStart = -1;
        invalidate();
        break;
    

    return result;


我无法弄清楚这里出了什么问题?

【问题讨论】:

【参考方案1】:

您的错误日志会为您完成大部分工作:

java.lang.ClassCastException: com.android.layoutlib.bridge.android.BridgeContext cannot be cast to com.android2.calculator3.Calculator
at com.android2.calculator3.view.ColorButton.<init>(ColorButton.java:39)

本质上,您正在尝试将BridgeContext 转换为Calculator,我假设它指的是您的构造函数中的这一行:

public ColorButton(Context context, AttributeSet attrs) 
    super(context, attrs);
    Calculator calc = (Calculator) context; //This Line
    init(calc);
    mListener = calc.mListener;
    setOnClickListener(mListener);
    setOnLongClickListener(mListener);

为此,您的context 参数需要从Calculator 继承。一个简单的测试是:

if (context instanceof Calculator) 
    Calculator calc = (Calculator) context;
 else 
    Log.e("Log Tag", context.toString() + " must inherit from Calculator class");

或者,使用try/catch 块:

try 
    Calculator calc = (Calculator) context;
 catch (ClassCastException e) 
    Log.e("Log Tag", context.toString() + " must inherit from Calculator class");
    e.printStackTrace();

编辑:

对您的情况可能的解决方法是对您的构造函数进行以下修改:

public ColorButton(Context context, AttributeSet attrs, Caculator calculator) 
    super(context, attrs);
    Calculator calc = calculator;
    init(calc);
    mListener = calc.mListener;
    setOnClickListener(mListener);
    setOnLongClickListener(mListener);

当然,这是因为我对您的自定义 Calculator 类一无所知(即,它是否甚至是 Context 的子类)。此方法将完全绕过 context 强制转换,因此您可以为第一个参数传递您喜欢的任何内容,只要它继承自 Context 类(最常见的是 Activity)。

【讨论】:

是的,就是这样。任何建议如何修复此代码以使其正常工作?计算器 calc = (计算器) 上下文; @Anna6541 好吧,你只需要确保无论你在哪里调用 ColorButton 类的构造函数,你都要确保作为它的第一个参数传递的任何东西都是 Calculator 类型 :) 谢谢,我会试试的,我是编程新手 :) @Anna6541 没问题。 FWIW,我在我的答案中添加了一些可能对你也有帮助的东西。如果它解决了您的问题,请不要忘记将答案标记为已接受。 我使用 if (!isInEditMode()) 现在工作正常。谢谢!

以上是关于调用自定义 Button 类的构造函数时出现 ClassCastException的主要内容,如果未能解决你的问题,请参考以下文章

我从 QThread 调用 QTcpSocket 类的写入函数时出现错误

不兼容的 Spring 依赖项(调用 AnnotationRepositoryConfigurationSource 构造函数时出现 NoSuchMethodError)

在scala中调用collect()函数时出现异常

访问自定义类的 IEnumerable<T> 时出现 NullReferenceException [重复]

为啥我在将 unique_ptr 返回给模板类的对象的函数定义时出现错误?

Android - 调用自定义 View 方法时出现空指针异常