0

I have some problem. Here in my code I am trying to redraw drawing drawn on board on screen rotation. but I am getting Null Object Reference exception

In my code bitmaps is an Bitmap arraylist.

Here's my saveInstanceState code

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

Here is 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();

    }
}

Here is my onRestoreInstanceState code

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

my redraww method

public void redraww()
    {
        try{

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

    }

drawView.redraw() method (Here is where I get my exception. I have logged it)

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

Here is my log

 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.access$900(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)

The drawing is not redrawn on screen rotation instead I am getting this exception.I am unable to resolve it. Please help..

EDIT: My java code of the program

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


}
Jishnu Mk
  • 143
  • 1
  • 3
  • 12

3 Answers3

0

drawCanvas is null in the method redraw(). Make sure that you instantiate drawCanvas before you call the redraw() method.

Posting full code will help, on where the issue lies though.

The problem is in your onRestoreInstanceState(). Your objects are not yet initialized and before that you are calling redraww. I would suggest you remove onRestoreInstanceState() and handle this in onCreate() itself to avoid code duplication.

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`.
}
Henry
  • 17,490
  • 7
  • 63
  • 98
  • I have updated my question with full code. Please do have a look. – Jishnu Mk Oct 25 '15 at 14:45
  • I tried as you said. And called redraww after all object initialization in onCreate method. But still same exception.:( – Jishnu Mk Oct 25 '15 at 14:56
  • I would suggest you create the `drawCanvas` object inside `setupDrawing()` method. – Henry Oct 25 '15 at 15:17
  • Hey i solved it. I called onWindowsFocusChanged and called my method from there and it worked. thanks for helping out. I will add the answer for other users. – Jishnu Mk Oct 25 '15 at 15:19
0

Move this code into the constructor of your 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());
JJF
  • 2,681
  • 2
  • 18
  • 31
  • Its not possible to do that. **onSizedChanged** method of View class. It cannot be moved into DrawingView constructor. – Jishnu Mk Oct 25 '15 at 15:31
  • Not the method. Just the code that's in the body of the onSizeChanged. Why are you initializing canvasBitmap, drawCanvas, etc. in that method? It make more sense to do it in the constructor. Is onSizeChagned getting called before you use those variables (set a breakpoint in the debugger). I'm thinking not. – JJF Oct 25 '15 at 15:38
  • I had called onSizeChanged to get the size of the view and set the canvasBitmap according to it. If i move the code from there to constructor I wont get the size of view. @ JJF – Jishnu Mk Oct 25 '15 at 15:45
  • What I guess I'm asking is did you set a breakpoint in onSizeChanged? Did you hit the breakpoint and instantiate your drawCanvase before redraw gets called? I doubt it because drawCanvas is null in redraw and the only place you intantiate it is onSizeChanged. Your're going to have to restructure things because things are not happening in the order you think they are. – JJF Oct 25 '15 at 15:49
  • I set breakpoint on onSizeChanged. I found that its called when the drawing view is created. – Jishnu Mk Oct 25 '15 at 16:59
0

Hey I found solution to my problem, with help of Henry. He pointed out that I was calling redraww() method before initializing objects. So I solved my issue by calling my method in onWindowFocusChanged.

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

I have set flag2 so that it doesnt invoke redraww() method on first creation of the activity. It should be invoked only when there is saveInstanceState.

Community
  • 1
  • 1
Jishnu Mk
  • 143
  • 1
  • 3
  • 12