Android: 尝试调用空对象引用的虚方法

Android: Attempt to invoke virtual method a null object reference

我有一些问题。在我的代码中,我试图重绘屏幕旋转时在船上绘制的图形。但我收到空对象引用异常

在我的代码中 bitmaps 是位图数组列表。

这是我的 saveInstanceState 代码

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    bitArrayStore(j);
    outState.putParcelableArrayList("Bits", bitmaps);
    outState.putInt("j", j);
}

这里是 bitArrayStore()

public void bitArrayStore(int k) {

    if (drawView.canvasBitmap.sameAs(drawView.emptyBitmap)) {
        flag = true;
    } else {

        try {
            if (flag1 == false) {
                drawView.buildDrawingCache();
                drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
                bitmaps.set(k, Bitmap.createBitmap(drawView.getDrawingCache()));

            } else {
                bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));
                flag1 = false;
            }
        } catch (IndexOutOfBoundsException e) {
            bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));

        }
        drawView.destroyDrawingCache();

    }
}

这是我的 onRestoreInstanceState 代码

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    bitmaps=savedInstanceState.getParcelableArrayList("Bits");
    j = savedInstanceState.getInt("j");
    redraww();
}

我的重绘方法

public void redraww()
    {
        try{

            drawView.redraw(bitmaps, j);
        }catch (IndexOutOfBoundsException e){
            drawView.startNew();
        }

    }

drawView.redraw() 方法(这是我得到异常的地方。我已经记录了它)

public void redraw(ArrayList<Bitmap> bits, int i) {
    try {

        drawCanvas.drawBitmap(bits.get(i), 0, 0, canvasPaint);
        invalidate();
    }catch (NullPointerException e){
        Log.w("Notepad",e);
    }
}

这是我的日志

 10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)' on a null object reference
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at org.notepad.notepad.notespage.DrawingView.redraw(DrawingView.java:145)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at org.notepad.notepad.notespage.NewNote.redraww(NewNote.java:368)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at org.notepad.notepad.notespage.NewNote.onRestoreInstanceState(NewNote.java:395)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.Activity.performRestoreInstanceState(Activity.java:978)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1162)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3947)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.ActivityThread.access0(ActivityThread.java:151)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.os.Handler.dispatchMessage(Handler.java:102)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.os.Looper.loop(Looper.java:135)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at android.app.ActivityThread.main(ActivityThread.java:5254)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at java.lang.reflect.Method.invoke(Native Method)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at java.lang.reflect.Method.invoke(Method.java:372)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
10-25 09:58:19.826 12664-12664/org.notepad.notepad W/Notepad:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

绘图没有在屏幕旋转时重新绘制,而是我得到这个 exception.I 我无法解决它。请帮忙..

编辑:我的java程序代码

NewNote.java

public class NewNote extends AppCompatActivity implements View.OnClickListener {


    private DrawingView drawView;
    private ImageButton currPaint;
    private float smallBrush = 5, mediumBrush = 10, largeBrush = 30;
    String ucolor;
    int i = 0, j = 0;
    private boolean flag = false, flag1 = false;
    ArrayList<Bitmap> bitmaps;
    Bitmap[] bits;
    @Bind(R.id.colornsize)
    ViewGroup colorNsize;
    @Bind(R.id.eraserdrawer)
    ViewGroup eraserDrawer;
    @Bind(R.id.blue_paint)
    ImageButton bluePaint;
    @Bind(R.id.small_brush)
    ImageButton smallBtn;
    @Bind(R.id.medium_brush)
    ImageButton mediumBtn;
    @Bind(R.id.large_brush)
    ImageButton largeBtn;
    @Bind(R.id.small_eraser)
    ImageButton smallEraser;
    @Bind(R.id.medium_eraser)
    ImageButton mediumEraser;
    @Bind(R.id.large_eraser)
    ImageButton largeEraser;
    @Bind(R.id.bottom_drawer)
    ViewGroup btm;
    @Bind(R.id.previousbtn)
    ImageButton previousBtn;
    @Bind(R.id.nextbtn)
    ImageButton nextBtn;
    @Bind(R.id.framelayout)
    FrameLayout frameLayout;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.notespage_newnote);
        ButterKnife.bind(this);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);


        drawView = (DrawingView) findViewById(R.id.drawing);
        currPaint = bluePaint;
        currPaint.setImageResource(R.drawable.paint_pressed);
        smallBrush = getResources().getInteger(R.integer.small_size);
        mediumBrush = getResources().getInteger(R.integer.medium_size);
        largeBrush = getResources().getInteger(R.integer.large_size);
        drawView.setBrushSize(mediumBrush);
        bitmaps = new ArrayList<Bitmap>();
        bits = new Bitmap[40];
        drawView.setDrawingCacheEnabled(true);
        smallBtn.setOnClickListener(this);
        mediumBtn.setOnClickListener(this);
        largeBtn.setOnClickListener(this);
        smallEraser.setOnClickListener(this);
        mediumEraser.setOnClickListener(this);
        largeEraser.setOnClickListener(this);
        previousBtn.setOnClickListener(this);
        nextBtn.setOnClickListener(this);




        drawView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        btm.setVisibility(View.GONE);
                        break;
                    case MotionEvent.ACTION_UP:
                        btm.setVisibility(View.VISIBLE);
                        break;
                    default:
                        return false;
                }

                return false;
            }
        });


    }


    public void paintClicked(View view) {
        //use chosen color
        drawView.setErase(false);
        drawView.setBrushSize(drawView.getLastBrushSize());
        if (view != currPaint) {
            //update color
            ImageButton imgView = (ImageButton) view;
            String color = view.getTag().toString();
            drawView.setColor(color);

            imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
            currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
            currPaint = (ImageButton) view;
        }
        hideDrawer(colorNsize);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.newnote_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.clear_menuitem) {
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
            newDialog.setTitle("Clear Board");
            newDialog.setMessage("Do you want to clear the board (you will lose the current drawing)?");
            newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    drawView.startNew();
                    bitmaps.remove(j);
                    flag1 = true;

                    dialog.dismiss();
                }
            });
            newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });
            newDialog.show();

            return true;
        } else if (id == R.id.save_menuitem) {
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            bitArrayStore(j);
            int k = 0;
            try {

                while (k <= bitmaps.size()) {


                    Bitmap m = null;

                    m = bitmaps.get(k);

                    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
                    File file = new File(path + File.separator + "Pictures" + File.separator + k + "_image.png");
                    FileOutputStream ostream;
                    try {
                        file.createNewFile();
                        ostream = new FileOutputStream(file);
                        m.compress(Bitmap.CompressFormat.PNG, 100, ostream);
                        ostream.flush();
                        ostream.close();

                        final Snackbar snackbar = Snackbar.make(frameLayout, "Note Saved", Snackbar.LENGTH_LONG);
                        snackbar.setAction("Close", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                snackbar.dismiss();
                            }
                        });
                        snackbar.show();

                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.w("Skoolify", e);
                    }
                    k = k + 1;
                }
            } catch (IndexOutOfBoundsException e) {
                Log.w("Skoolify", "OutOFBonds");
            }
            return true;
        } else if (id == R.id.brush_menuitem) {
            if (colorNsize.getVisibility() == View.VISIBLE) {
                hideDrawer(colorNsize);
            } else {
                hideDrawer(eraserDrawer);
                showDrawer(colorNsize);
            }

            return true;
        } else if (id == R.id.eraser_menuitem) {
            if (eraserDrawer.getVisibility() == View.VISIBLE) {
                hideDrawer(eraserDrawer);
            } else {
                hideDrawer(colorNsize);
                showDrawer(eraserDrawer);
            }

            return true;
        }

        else if(id==R.id.delete_menuitem){
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
            newDialog.setTitle("Discard the Notes");
            newDialog.setMessage("Do you want to discard the unsaved notes?");
            newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    NewNote.this.finish();

                    dialog.dismiss();
                }
            });
            newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });
            newDialog.show();

        }

        return super.onOptionsItemSelected(item);
    }


    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.small_brush) {
            drawView.setBrushSize(smallBrush);
            drawView.setLastBrushSize(smallBrush);
            drawView.setErase(false);
            hideDrawer(colorNsize);
        } else if (v.getId() == R.id.medium_brush) {
            drawView.setBrushSize(mediumBrush);
            drawView.setLastBrushSize(mediumBrush);
            drawView.setErase(false);
            hideDrawer(colorNsize);
        } else if (v.getId() == R.id.large_brush) {
            drawView.setBrushSize(largeBrush);
            drawView.setLastBrushSize(largeBrush);
            drawView.setErase(false);
            hideDrawer(colorNsize);
        } else if (v.getId() == R.id.small_eraser) {
            drawView.setErase(true);
            drawView.setBrushSize(smallBrush);
            hideDrawer(eraserDrawer);
        } else if (v.getId() == R.id.medium_eraser) {
            drawView.setErase(true);
            drawView.setBrushSize(mediumBrush);
            hideDrawer(eraserDrawer);
        } else if (v.getId() == R.id.large_eraser) {
            drawView.setErase(true);
            drawView.setBrushSize(largeBrush);
            hideDrawer(eraserDrawer);
        } else if (v.getId() == R.id.previousbtn) {
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            try {
                bitArrayStore(j);
                drawView.startNew();
                j--;
                if (bitmaps.size() > j) {
                    drawView.redraw(bitmaps, j);
                }
            } catch (IndexOutOfBoundsException e) {
                j = 0;
                try {
                    drawView.redraw(bitmaps, j);
                }catch (IndexOutOfBoundsException e1){
                    drawView.startNew();
                }
            }
            flag = false;
        } else if (v.getId() == R.id.nextbtn) {
            hideDrawer(colorNsize);
            hideDrawer(eraserDrawer);
            if (j < 50) {
                bitArrayStore(j);
                if (flag == false) {
                    j++;
                }
                if (bitmaps.size() > j) {
                    drawView.startNew();
                    drawView.redraw(bitmaps, j);
                } else {
                    drawView.startNew();
                }
                flag = false;
            } else {
                Snackbar.make(v, "Reached page limit. Please save and start new note", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }

        }


    }


    public void bitArrayStore(int k) {

        if (drawView.canvasBitmap.sameAs(drawView.emptyBitmap)) {
            flag = true;
        } else {

            try {
                if (flag1 == false) {
                    drawView.buildDrawingCache();
                    drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
                    bitmaps.set(k, Bitmap.createBitmap(drawView.getDrawingCache()));

                } else {
                    bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));
                    flag1 = false;
                }
            } catch (IndexOutOfBoundsException e) {
                bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));

            }
            drawView.destroyDrawingCache();

        }
    }

    public void redraww()
    {
        try{

            drawView.redraw(bitmaps, j);
        }catch (IndexOutOfBoundsException e){
            drawView.startNew();
        }

    }
    public void hideDrawer(ViewGroup viewgrp) {
        viewgrp.setVisibility(View.GONE);
    }

    public void showDrawer(ViewGroup viewgrp) {
        viewgrp.setVisibility(View.VISIBLE);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        bitArrayStore(j);
        outState.putParcelableArrayList("Bits", bitmaps);
        outState.putInt("j", j);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        bitmaps=savedInstanceState.getParcelableArrayList("Bits");
        j = savedInstanceState.getInt("j");
        redraww();

    }
}

DrawingView.java

public class DrawingView extends View {

    //drawing path
    private Path drawPath;
    //drawing and canvas paint
    private Paint drawPaint, canvasPaint;
    //initial color
    private int paintColor = 0xFF0000c4;
    //canvas
    private Canvas drawCanvas;
    //canvas bitmap
    public Bitmap canvasBitmap, emptyBitmap;
    private float brushSize, lastBrushSize;
    private boolean erase = false;


    public DrawingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupDrawing();
    }

    private void setupDrawing() {
        brushSize = getResources().getInteger(R.integer.small_size);
        lastBrushSize = brushSize;
        drawPath = new Path();
        drawPaint = new Paint();
        drawPaint.setColor(paintColor);
        drawPaint.setAntiAlias(true);
        drawPaint.setStrokeWidth(20);
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);
        canvasPaint = new Paint(Paint.DITHER_FLAG);
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//view given size
        super.onSizeChanged(w, h, oldw, oldh);
        canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
        emptyBitmap = Bitmap.createBitmap(canvasBitmap.getWidth(), canvasBitmap.getHeight(), canvasBitmap.getConfig());
    }

    @Override
    protected void onDraw(Canvas canvas) {
//draw view
        canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
        canvas.drawPath(drawPath, drawPaint);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
//detect user touch
        float touchX = event.getX();
        float touchY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                drawPath.moveTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                drawPath.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                drawCanvas.drawPath(drawPath, drawPaint);
                drawPath.reset();
                break;
            default:
                return false;
        }
        invalidate();
        return true;
    }

    public void setColor(String newColor) {
//set color
        invalidate();
        paintColor = Color.parseColor(newColor);
        drawPaint.setColor(paintColor);
    }

    public void setBrushSize(float newSize) {
//update sizefloat pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
        float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                newSize, getResources().getDisplayMetrics());
        brushSize = pixelAmount;
        drawPaint.setStrokeWidth(brushSize);
    }

    public void setLastBrushSize(float lastSize) {
        lastBrushSize = lastSize;
    }

    public float getLastBrushSize() {
        return lastBrushSize;
    }

    public void setErase(boolean isErase) {
//set erase true or false
        erase = isErase;
        if (erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        else drawPaint.setXfermode(null);
    }

    public void startNew() {
        drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        invalidate();


//        Bitmap b= BitmapFactory.decodeFile("/storage/emulated/0/Pictures/image.png");
//        drawCanvas.drawBitmap(b, 0, 0, null);
//
//        invalidate();

    }


    public void redraw(ArrayList<Bitmap> bits, int i) {
        try {

                drawCanvas.drawBitmap(bits.get(i), 0, 0, canvasPaint);
                invalidate();


        }catch (NullPointerException e){
            Log.w("DrawingApp","Exception");
        }
    }


}

drawCanvas 在方法 redraw() 中为 null。确保在调用 redraw() 方法之前实例化 drawCanvas

不过,发布完整代码会有所帮助,了解问题所在。

问题出在您的 onRestoreInstanceState() 上。您的对象尚未初始化,在此之前您正在调用 redraww。我建议您删除 onRestoreInstanceState() 并在 onCreate() 中处理它以避免代码重复。

protected void onCreate(Bundle savedInstanceState){
      if(savedInstanceState != null){
            bitmaps=savedInstanceState.getParcelableArrayList("Bits");
            j = savedInstanceState.getInt("j");
     }

     // go ahead with your object initialization. Once your `drawCanvas` is ready and initialized, then call `redraww`.
}

将此代码移动到 DrawingView 的构造函数中 class。

//view given size
        super.onSizeChanged(w, h, oldw, oldh);
        canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
        emptyBitmap = Bitmap.createBitmap(canvasBitmap.getWidth(), canvasBitmap.getHeight(), canvasBitmap.getConfig());

嘿,在 Henry 的帮助下,我找到了解决问题的方法。他指出我在初始化对象之前调用了 redraww() 方法。所以我通过在 onWindowFocusChanged 中调用我的方法解决了我的问题。

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if (hasFocus) {
            if (flag2 == true) {
                redraww();
            }
        }
    }

我已经设置了 flag2,这样它就不会在第一次创建 activity 时调用 redraww() 方法。仅当存在 saveInstanceState 时才应调用它。