Search code examples
androidandroid-layoutandroid-custom-view

Android: Custom view 'PointsView': Error "The following classes could not be instantiated"


I'm creating an Android Yahtzee game app. To keep track of player scores, I've tried to create a PointsView class to hold these scores. However, I'm getting a "The following classes could not be instantiated: - uk.ac.surrey.jb00359.yatzy.PointsView... See Error Log (Window > Show View)..." error for PointsView when I try to create it within my game XML layout file, shown below.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="@color/background_colour" >

  <Button
    android:id="@+id/roll_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_marginBottom="@dimen/die_margin"
    android:layout_marginLeft="@dimen/die_margin"
    android:text="@string/roll_button_text" />

  <TextView
    android:id="@+id/player_turn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/roll_button"
    android:layout_alignParentRight="true"
    android:layout_marginRight="@dimen/die_margin"
    android:text="@string/player_1_turn_text"
    android:textSize="18sp" />

  <ImageView
    android:id="@+id/die_3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/roll_button"
    android:layout_marginBottom="@dimen/die_margin"
    android:layout_centerHorizontal="true"
    android:contentDescription="@string/die_3_description"
    android:src="@drawable/dice_1" />

  <ImageView
    android:id="@+id/die_2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/die_3"
    android:layout_toLeftOf="@id/die_3"
    android:layout_marginRight="@dimen/die_margin"
    android:contentDescription="@string/die_2_description"
    android:src="@drawable/dice_1" />

  <ImageView
    android:id="@+id/die_1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/die_2"
    android:layout_toLeftOf="@id/die_2"
    android:layout_marginRight="@dimen/die_margin"
    android:contentDescription="@string/die_1_description"
    android:src="@drawable/dice_1" /> 

  <ImageView
    android:id="@+id/die_4"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/die_3"
    android:layout_toRightOf="@id/die_3"
    android:layout_marginLeft="@dimen/die_margin"
    android:contentDescription="@string/die_4_description"
    android:src="@drawable/dice_1" />

  <ImageView
    android:id="@+id/die_5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/die_4"
    android:layout_toRightOf="@id/die_4"
    android:layout_marginLeft="@dimen/die_margin"
    android:contentDescription="@string/die_5_description"
    android:src="@drawable/dice_1" />

  <uk.ac.surrey.jb00359.yatzy.PointsView
    android:id="@+id/points_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="@dimen/points_view_margin"
    android:layout_marginTop="@dimen/points_view_margin"
    android:layout_marginRight="@dimen/points_view_margin"
    android:layout_marginBottom="@dimen/die_margin"
    android:layout_above="@id/die_1" />

</RelativeLayout>

When I look up the error log, it gives me this exception stack trace:

java.lang.NoSuchMethodException: uk.ac.surrey.jb00359.yatzy.PointsView.<init>(android.content.Context, android.util.AttributeSet)
    at java.lang.Class.getConstructor0(Class.java:2733)
    at java.lang.Class.getConstructor(Class.java:1676)
    at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:347)
    at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:179)
    at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207)
    at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:135)
    at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:746)
    at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:718)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:372)
    at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:385)
    at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:332)
    at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:325)
    at com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService.createRenderSession(RenderService.java:440)
    at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.renderWithBridge(GraphicalEditorPart.java:1545)
    at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.recomputeLayout(GraphicalEditorPart.java:1302)
    at com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart.activated(GraphicalEditorPart.java:1059)
    at com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate.delegatePageChange(LayoutEditorDelegate.java:686)
    at com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor.pageChange(CommonXmlEditor.java:360)
    at org.eclipse.ui.part.MultiPageEditorPart$2.widgetSelected(MultiPageEditorPart.java:292)
    at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:248)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1276)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1300)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1285)
    at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:1079)
    at org.eclipse.swt.custom.CTabFolder.setSelection(CTabFolder.java:3023)
    at org.eclipse.swt.custom.CTabFolder.onMouse(CTabFolder.java:1730)
    at org.eclipse.swt.custom.CTabFolder$1.handleEvent(CTabFolder.java:270)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1276)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3554)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3179)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1022)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:916)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:86)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:585)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:540)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:584)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1438)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1414)

So far, I have tried overriding my PointView's onMeasure() method using code kindly provided by stackoverflow user Devunwired at "onMeasure custom view explanation", but so far with no noticeable success. (See below)

package uk.ac.surrey.jb00359.yatzy;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.View;

/**
 * 
 * This class outputs the current scores obtained by the two Yatzy players
 */
public class PointsView extends View {

// Do not change these values!
private static final float noOfColumns = 3f;
private static final float noOfRows = 19f;

private GameActivity game;
private GameLogic gameLogic;
private Paint majorLinePaint = new Paint();
private Paint minorLinePaint = new Paint();
/** 
  * Colour of score cells, that can be selected to store
  * a player's new dice score after a round (1-3 dice throws)
  */
private Paint selectablePaint = new Paint();
private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float top, left, bottom, right; // grid boundaries
private float cellWidth, cellHeight; // Cell sizes

public PointsView(Context context, AttributeSet attrs, GameLogic gameLogic) {
    super(context, attrs);
    // Allow the view to refer to the game activity and game logic (state) 
    this.game = (GameActivity) context;
    this.gameLogic = gameLogic;
    majorLinePaint.setColor(getResources().getColor(R.color.major_line_colour));
    minorLinePaint.setColor(getResources().getColor(R.color.minor_line_colour));
    selectablePaint.setColor(getResources().getColor(R.color.selectable_cell_colour));
    textPaint.setColor(getResources().getColor(R.color.text_colour));
    textPaint.setStyle(Style.FILL);
    textPaint.setTextScaleX(1f);
    textPaint.setTextAlign(Paint.Align.CENTER); 
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    top = 0;
    left = 0;
    bottom = h;
    right = w;
    cellWidth = w / noOfColumns; // 3 columns of cells
    cellHeight = h / noOfRows; // 19 rows of cells
    // Set text size to be 7/8 of the height of each cell
    textPaint.setTextSize(cellHeight * (7/8));
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {
    // Draw the PointsView's grid lines
    for (int i = 0; i <= noOfColumns; i++) {
        // Draw column lines
        canvas.drawLine(left + i*cellWidth, top, left + i*cellWidth, bottom, majorLinePaint);
    }
    for (int j = 0; j <= noOfRows; j++) {
        // Draw row lines
        canvas.drawLine(left, top + j*cellHeight, right, top + j*cellHeight, majorLinePaint);
    }

    // More drawing later...

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    /** 
     * Here starts Devunwired's code from 
     * https://stackoverflow.com/questions/12266899/onmeasure-custom-view-explanation */

    int desiredWidth = 100;
    int desiredHeight = 100;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
        //Must be this size
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        width = Math.min(desiredWidth, widthSize);
    } else {
        //Be whatever you want
        width = desiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
        //Must be this size
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        height = Math.min(desiredHeight, heightSize);
    } else {
        //Be whatever you want
        height = desiredHeight;
    }

    //MUST CALL THIS
    setMeasuredDimension(width, height);

    /** End of Devunwired's code */
}

}

Would anyone know what's happening in my code to cause this error?


Solution

  • Try to add 2 constructors:

    public PointsView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
        }
    
        public PointsView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
        }