使用“id”而不是“android:id”会导致NullPointerException

时间:2018-04-07 03:40:27

标签: java android canvas nullpointerexception

我创建了一个View的子类,用于绘制三角形。 TriangleDrawView如下所示。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.support.v4.content.res.ResourcesCompat;
import android.util.AttributeSet;
import android.view.View;

public class TriangleDrawView extends View {

    private Paint mPaint;
    private Path mPath;
    private int mDrawColor;
    private int mBackgroundColor;
    private Canvas mExtraCanvas;
    private Bitmap mExtraBitmap;

    private int paddingX, paddingY;
    private int drawableRectX,drawableRectY;
    private int triangleBoundX,triangleBoundY;
    private int total_width,total_height;
    private double angle_a,angle_b,angle_c;
    private int xA,xB,xC,yA,yB,yC;

    public TriangleDrawView(Context context) {
        this(context,null);
    }

    public TriangleDrawView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mBackgroundColor = ResourcesCompat.getColor(getResources(),
                R.color.opaque_orange, null);
        mDrawColor = ResourcesCompat.getColor(getResources(),
                R.color.opaque_yellow, null);

        // Holds the path we are currently drawing.
        mPath = new Path();
        // Set up the paint with which to draw.
        mPaint = new Paint();
        mPaint.setColor(mDrawColor);
        // Smoothes out edges of what is drawn without affecting shape.
        mPaint.setAntiAlias(true);
        // Dithering affects how colors with higher-precision device
        // than the are down-sampled.
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE); // default: FILL
        mPaint.setStrokeJoin(Paint.Join.ROUND); // default: MITER
        mPaint.setStrokeCap(Paint.Cap.ROUND); // default: BUTT
        mPaint.setStrokeWidth(5); // default: Hairline-width (really thin)

        angle_a = Math.PI/3;
        angle_b = Math.PI/3;
        angle_c = Math.PI/3;

        paddingX = 100;
        paddingY = 100;
    }


    @Override
    protected void onSizeChanged(int width, int height,
                                 int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);

        // Create bitmap, create canvas with bitmap, fill canvas with color.
        mExtraBitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);
        mExtraCanvas = new Canvas(mExtraBitmap);
        // Fill the Bitmap with the background color.
        mExtraCanvas.drawColor(mBackgroundColor);

        total_width = width;
        total_height = height;
        drawTriangle(angle_a,angle_b,angle_c);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Draw the bitmap that stores the path the user has drawn.
        // Initially the user has not drawn anything
        // so we see only the colored bitmap.
        canvas.drawBitmap(mExtraBitmap, 0, 0, null);
    }


    private void initTriangleBounds(double angle_b, double angle_c, int total_width,int total_height, int paddingX, int paddingY){
        drawableRectX = total_width-2*paddingX;
        drawableRectY=total_height-2*paddingY;

        int x_,y_;
        x_ = total_width/2;
        y_ = total_height/2;

        if(angle_b<Math.PI/2 && angle_c<Math.PI/2 ){
            if(drawableRectX >= ( drawableRectY/Math.tan(angle_b) + drawableRectY/Math.tan(angle_c) ) ){
                triangleBoundY =  drawableRectY;
                triangleBoundX = (int)( drawableRectY/Math.tan(angle_b) + drawableRectY/Math.tan(angle_c) );
            }else{
                triangleBoundX = drawableRectX;
                triangleBoundY = (int) ( drawableRectX/( 1/Math.tan(angle_b) +1/Math.tan(angle_c) ) );
            }

            xB = x_ - triangleBoundX/2;
            yB = y_ + triangleBoundY/2;

            xC = x_ + triangleBoundX/2;
            yC = yB;

            yA = y_ - triangleBoundY/2;
            xA = xB + (int)(triangleBoundY/Math.tan(angle_b));

        }else if(angle_b>=Math.PI/2){
            if( drawableRectX <= ( drawableRectY/Math.tan(angle_c) )){
                triangleBoundY =  drawableRectY;
                triangleBoundX = (int)( drawableRectY/Math.tan(angle_c));
            }else{
                triangleBoundX = drawableRectX;
                triangleBoundY = (int)( drawableRectX * Math.tan(angle_c));
            }

            xA = x_ - triangleBoundX/2;
            yA = y_ - triangleBoundY/2;

            xC = x_ + triangleBoundX/2;
            yC = y_ + triangleBoundY/2;

            xB = xA + (int)(triangleBoundY/Math.tan(Math.PI - angle_b));
            yB = yC;
        }else if(angle_c>=Math.PI/2){
            if( drawableRectX <= ( drawableRectY/Math.tan(angle_b) )){
                triangleBoundY =  drawableRectY;
                triangleBoundX = (int)( drawableRectY/Math.tan(angle_b));
            }else{
                triangleBoundX = drawableRectX;
                triangleBoundY = (int)( drawableRectX * Math.tan(angle_b));
            }

            xA = x_ + triangleBoundX/2;
            yA = y_ - triangleBoundY/2;

            xB = x_ - triangleBoundX/2;
            yB = y_ + triangleBoundY/2;

            xC = xA - (int)(triangleBoundY/Math.tan(Math.PI - angle_c));
            yC = yB;
        }
    }

    public void drawTriangle(double angle_a, double angle_b, double angle_c){
        this.angle_a = angle_a;
        this.angle_b = angle_b;
        this.angle_c = angle_c;
        initTriangleBounds(angle_b,angle_c,total_width,total_height,paddingX,paddingY);

        mPath.moveTo(xA, yA);
        mPath.quadTo(xA,yA,xB,yB);
        mPath.quadTo(xB,yB,xC,yC);
        mPath.quadTo(xC,yC,xA,yA);
        mExtraCanvas.drawPath(mPath, mPaint);
        invalidate();
    }


}

现在,此TriangleDrawView已包含在活动中,如下所示。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="my.canvas2.TestingActivity">

    <view
        class="my.canvas2.TriangleDrawView"
        id="@+id/viewTriangle"
        android:layout_width="273dp"
        android:layout_height="302dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:onClick="onClick"/>
</android.support.constraint.ConstraintLayout>

当活动开始时,它可以正常工作,如下面的屏幕截图所示。 enter image description here

我需要做的是调用public void drawTriangle(double angle_a, double angle_b, double angle_c)的{​​{1}}方法。因此,在Activity的按钮的onClick方法中,我调用了TriangleDrawView方法,如下所示。

drawTriangle

但是当点击按钮时,应用程序崩溃了import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; public class TestingActivity extends AppCompatActivity { private TriangleDrawView triangleDrawView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_testing); triangleDrawView = findViewById(R.id.viewTriangle); } public void onClick(View view) { double pi = Math.PI; //Method implemented triangleDrawView.drawTriangle(pi/2,pi/3,pi/6); } } 。这是LogCat输出;

NullPointerException

更新

this问题中对FATAL EXCEPTION: main Process: my.canvas2, PID: 15645 java.lang.IllegalStateException: Could not execute method for android:onClick at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293) at android.view.View.performClick(View.java:6294) at android.view.View$PerformClick.run(View.java:24770) at android.os.Handler.handleCallback(Handler.java:790) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) at android.view.View.performClick(View.java:6294)  at android.view.View$PerformClick.run(View.java:24770)  at android.os.Handler.handleCallback(Handler.java:790)  at android.os.Handler.dispatchMessage(Handler.java:99)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6494)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)  Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void my.canvas2.TriangleDrawView.drawTriangle(double, double, double)' on a null object reference at my.canvas2.TestingActivity.onClick(TestingActivity.java:24) at java.lang.reflect.Method.invoke(Native Method)  at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)  at android.view.View.performClick(View.java:6294)  at android.view.View$PerformClick.run(View.java:24770)  at android.os.Handler.handleCallback(Handler.java:790)  at android.os.Handler.dispatchMessage(Handler.java:99)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6494)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)  进行了详细解释。但它并没有解决我的问题。我通过Mike MTomas Jablonskis的答案成功解决了问题。

  

元素上的id属性必须具有android前缀。   也就是说,android:id =“@ + id / viewTriangle”。如果您的IDE,我会感到惊讶   并没有给出至少一个警告。

- Mike M

  

您的视图triangleDrawView未初始化,因为您使用   元素上的XML中的id属性,这就是原因所在   .findViewById(id)无法正确查找和初始化您的视图。

     

将id = ...更改为android:id = ...应该可以解决您的问题。

- Tomas Jablonskis

2 个答案:

答案 0 :(得分:1)

您的观看次数public function rules() { $rules = [ 'guest' => 'array' ]; foreach($this->request->get('guest') as $key => $val){ $rules['guest.'.$key.'. sleeps'] = 'required|not_in:0'; $rules['guest.'.$key.'. comments'] = 'max:300'; } return $rules; } 尚未初始化,因为您在triangleDrawView id元素上使用了XML属性,这就是<view ... >所做的原因找不到并正确初始化.findViewById(id)

View更改为id=...可以解决您的问题。

答案 1 :(得分:1)

使用调试来解决问题。某些值为null,因此它给出了空指针异常。在drawTraingle()方法中添加调试断点并检查哪个值为null。