简体   繁体   中英

Android: Android app crashing when trying to load saved Bitmap data to Canvas

First of all thanks in advance for the help. My app is basically a sketchbook with multiple canvas. Here after drawing on first canvas and when I click on Next button new canvas is loaded and previous canvas is saved into an Bitmap array. After drawing on the new canvas that has been loaded, when I click on Prev button, the present drawing is saved in bitmap array and the new canvas should load the previously drawn image onto canvas.

But instead of that when i click on Prev button the app is crashing.

Please help me with this issue.

Here is the code of both Next and Prev buttons.

Next Button

if(view.getId()==R.id.next){
        bitArrayStore(i);
        drawView.startNew();
        i++;
    }

Prev Button

if(view.getId() == R.id.prev){
        bitArrayStore(i);
        drawView.startNew();
        i--;
        drawView.redraw(bits, i);
    }

bitArrayStore()

 public void bitArrayStore(int k){

    drawView.buildDrawingCache();
    drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    bits[k] = drawView.getDrawingCache();
    drawView.destroyDrawingCache();
}

drawView.redraw()

 public void redraw(Bitmap[] bits, int i) {
    drawCanvas.drawBitmap(bits[i], 0, 0, null);
    invalidate();
}

Here is my logcat

10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime: FATAL EXCEPTION: main
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime: Process: com.example.jishnu.notestest, PID: 18856
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime: java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@c0446aa
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1282)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.graphics.Canvas.drawBitmap(Canvas.java:1337)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at com.example.jishnu.notestest.DrawingView.redraw(DrawingView.java:136)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at com.example.jishnu.notestest.MainActivity.onClick(MainActivity.java:245)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.view.View.performClick(View.java:4780)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.view.View$PerformClick.run(View.java:19866)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:135)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5254)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
10-16 03:23:45.816 18856-18856/com.example.jishnu.notestest E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

Here is my rest of the code in case of reference

MainActivity.java

public class MainActivity extends AppCompatActivity implements OnClickListener {

    private DrawingView drawView;
    private ImageButton currPaint,drawBtn,eraseBtn,newBtn,saveBtn;
    private float smallBrush, mediumBrush, largeBrush;
    String ucolor;
    private Button nextbtn,prevbtn;
    int i=0;
    Bitmap[] bits;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        drawView = (DrawingView) findViewById(R.id.drawing);
        LinearLayout paintLayout = (LinearLayout) findViewById(R.id.paint_colors);
        currPaint = (ImageButton) paintLayout.getChildAt(0);
        currPaint.setImageDrawable(getResources().getDrawable(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);
        drawBtn = (ImageButton)findViewById(R.id.draw_btn);
        drawBtn.setOnClickListener(this);
        drawView.setBrushSize(mediumBrush);
        eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
        eraseBtn.setOnClickListener(this);
        newBtn = (ImageButton)findViewById(R.id.new_btn);
        newBtn.setOnClickListener(this);
        saveBtn = (ImageButton)findViewById(R.id.save_btn);
        saveBtn.setOnClickListener(this);

        bits=new Bitmap[40];
        nextbtn=(Button)findViewById(R.id.next);
        prevbtn=(Button)findViewById(R.id.prev);
        nextbtn.setOnClickListener(this);
        prevbtn.setOnClickListener(this);
        drawView.setDrawingCacheEnabled(true);

    }

    public void paintClicked(View view) {
        //use chosen color

        drawView.setErase(false);
        drawView.setBrushSize(drawView.getLastBrushSize());
        if (view != currPaint) {

            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;
        }
    }

    @Override
    public void onClick(View view) {
        if(view.getId()==R.id.draw_btn){
            //draw button clicked
            final Dialog brushDialog = new Dialog(this);
            brushDialog.setTitle("Brush size:");
            brushDialog.setContentView(R.layout.brush_chooser);
            ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
            smallBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    drawView.setBrushSize(smallBrush);
                    drawView.setLastBrushSize(smallBrush);
                    drawView.setErase(false);

                    brushDialog.dismiss();
                }
            });
            ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
            mediumBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    drawView.setBrushSize(mediumBrush);
                    drawView.setLastBrushSize(mediumBrush);
                    drawView.setErase(false);

                    brushDialog.dismiss();
                }
            });

            ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
            largeBtn.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v) {
                    drawView.setBrushSize(largeBrush);
                    drawView.setLastBrushSize(largeBrush);
                    drawView.setErase(false);

                    brushDialog.dismiss();
                }
            });
            brushDialog.show();
        }
        else if(view.getId()==R.id.erase_btn){
            //switch to erase - choose size
            final Dialog brushDialog = new Dialog(this);
            brushDialog.setTitle("Eraser size:");
            brushDialog.setContentView(R.layout.brush_chooser);
            ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
            smallBtn.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v) {
                    drawView.setErase(true);
                    drawView.setBrushSize(smallBrush);
                    brushDialog.dismiss();
                }
            });
            ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
            mediumBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    drawView.setErase(true);
                    drawView.setBrushSize(mediumBrush);
                    brushDialog.dismiss();
                }
            });
            ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
            largeBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    drawView.setErase(true);
                    drawView.setBrushSize(largeBrush);
                    brushDialog.dismiss();
                }
            });
            brushDialog.show();
        }
        else if(view.getId()==R.id.new_btn){
            //new button
            AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
            newDialog.setTitle("New drawing");
            newDialog.setMessage("Start new drawing (you will lose the current drawing)?");
            newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
                public void onClick(DialogInterface dialog, int which){
                    drawView.startNew();
                    dialog.dismiss();
                }
            });
            newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
                public void onClick(DialogInterface dialog, int which){
                    dialog.cancel();
                }
            });
            newDialog.show();
        }

        else if(view.getId()==R.id.save_btn){
            //save drawing
            AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
            saveDialog.setTitle("Save drawing");
            saveDialog.setMessage("Save drawing to device Gallery?");
            saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
                public void onClick(DialogInterface dialog, int which){
                    //save drawing
                    drawView.setDrawingCacheEnabled(true);
                    drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
                    Bitmap bitmap = drawView.getDrawingCache();
                    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
                    File file = new File(path+File.separator+"Pictures"+File.separator+"image.png");
                    FileOutputStream ostream;
                    try {
                        file.createNewFile();
                        ostream = new FileOutputStream(file);
                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, ostream);
                        ostream.flush();
                        ostream.close();
                        Toast.makeText(getApplicationContext(), "image saved :"+path, Toast.LENGTH_SHORT).show();


                    } catch (Exception e) {
                        e.printStackTrace();
                        Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show();
                    }
                    drawView.destroyDrawingCache();
                }
            });
            saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
                public void onClick(DialogInterface dialog, int which){
                    dialog.cancel();
                }
            });
            saveDialog.show();
        }

        if(view.getId()==R.id.next){
            bitArrayStore(i);
            drawView.startNew();
            i++;
        }
        if(view.getId() == R.id.prev){
            bitArrayStore(i);
            drawView.startNew();
            i--;
            drawView.redraw(bits, i);
        }

    }

    public void bitArrayStore(int k){

        drawView.buildDrawingCache();
        drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        bits[k] = drawView.getDrawingCache();
        drawView.destroyDrawingCache();
    }

}

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 = 0xFF660000;
    //canvas
    private Canvas drawCanvas;
    //canvas bitmap
    private Bitmap canvasBitmap;
    private float brushSize, lastBrushSize;
    private boolean erase=false;

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

    private void setupDrawing() {
//get drawing area setup for interaction
        brushSize = getResources().getInteger(R.integer.medium_size);
        lastBrushSize = brushSize;
        drawPath = new Path();
        drawPaint = new Paint();
        drawPaint.setColor(paintColor);
        drawPaint.setAntiAlias(true);
        drawPaint.setStrokeWidth(brushSize);
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);

        canvasPaint = new Paint(Paint.DITHER_FLAG);
    }

    @Override
    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);
    }

    @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(Bitmap[] bits, int i) {
        drawCanvas.drawBitmap(bits[i], 0, 0, null);
        invalidate();
    }
}

Problem is when i click on Prev button the app is crashing. Can anyone please help me with this issue ?!

Instead of

bits[k] = drawView.getDrawingCache();

in bitArrayStore() method

It should be

bits[k] = Bitmap.createBitmap(drawView.getDrawingCache());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM