Say I have a custom Drawing View which is hosted in Main Activity. Right now I'm struggling with saving the drawing state when orientation of the device changes. I'm getting NullPointerException
AFTER orientation changes. So I can draw with no problem but after I rotate the device it crashes. Please give me a hint on that, I'm so frustrated. Here's my drawing view. Getting NPE in this line: drawCanvas.drawPath(drawPath, drawPaint);
when calling performTouchEvent()
after rotation
public class DrawingView extends View {
private static final String EXTRA_EVENT_LIST = "event_list";
private static final String EXTRA_STATE = "instance_state";
private ArrayList<MotionEvent> eventList = new ArrayList<MotionEvent>(100);
private ArrayList<MotionEvent> myObject = new ArrayList<MotionEvent>(100);
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000, paintAlpha = 255;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//brush sizes
private float brushSize, lastBrushSize;
//erase flag
private boolean erase=false;
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//setup drawing
private void setupDrawing(){
//prepare for drawing and setup paint stroke properties
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);
}
//size assigned to view
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
//draw the view - will be called after touch event
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
//register user touches as drawing action
@Override
public boolean onTouchEvent(MotionEvent event) {
getParent().requestDisallowInterceptTouchEvent(true);
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
performTouchEvent(event);
}
//redraw
invalidate();
eventList.add(MotionEvent.obtain(event));
return true;
}
private void performTouchEvent(MotionEvent event) {
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:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
}
invalidate();
eventList.add(MotionEvent.obtain(event));
}
//update color
public void setColor(String newColor){
invalidate();
//check whether color value or pattern name
if(newColor.startsWith("#")){
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
drawPaint.setShader(null);
}
else{
//pattern
int patternID = getResources().getIdentifier(
newColor, "drawable", "com.androbro.navigationdrawerproject");
//decode
Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID);
//create shader
BitmapShader patternBMPshader = new BitmapShader(patternBMP,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
//color and shader
drawPaint.setColor(0xFFFFFFFF);
drawPaint.setShader(patternBMPshader);
}
}
//set brush size
public void setBrushSize(float newSize){
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
//get and set last brush size
public void setLastBrushSize(float lastSize){
lastBrushSize=lastSize;
}
public float getLastBrushSize(){
return lastBrushSize;
}
//set erase true or false
public void setErase(boolean isErase){
erase=isErase;
if(erase) {
drawPaint.setColor(Color.WHITE);//set the color to white
}
else drawPaint.setColor(paintColor); //if erase is set to false, it will use the previous color.
}
//start new drawing
public void startNew(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
//return current alpha
public int getPaintAlpha(){
return Math.round((float)paintAlpha/255*100);
}
//set alpha
public void setPaintAlpha(int newAlpha){
paintAlpha=Math.round((float)newAlpha/100*255);
drawPaint.setColor(paintColor);
drawPaint.setAlpha(paintAlpha);
}
@Override
public Parcelable onSaveInstanceState()
{
Log.i("Saving", "drawing");
Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATE, super.onSaveInstanceState());
bundle.putParcelableArrayList(EXTRA_EVENT_LIST, eventList);
return bundle;
}
@Override
public void onRestoreInstanceState(Parcelable state)
{
Log.i("OnRestore", "state");
if (state instanceof Bundle)
{
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable(EXTRA_STATE));
eventList = bundle.getParcelableArrayList(EXTRA_EVENT_LIST);
if (eventList != null) {
Log.i("EventList", "is not null");
myObject = new ArrayList<>(eventList);
} else{
return;
}
for (MotionEvent event : myObject) {
Log.i("Event", "" + event);
performTouchEvent(event);
}
return;
}
super.onRestoreInstanceState(state);
}
}