1

I'm doing a small painting android application. I want to create a custom View to paint some thing on it. When a create a layout and add my View.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.androidpaint.PaintView 
android:id="@+id/paintPlace"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</RelativeLayout>

It got an error that

java.lang.NullPointerException
    Exception details are logged in Window > Show View > Error Log
    java.lang.NullPointerException
        at android.graphics.Canvas.drawPath(Canvas.java:1021)
        at com.example.androidpaint.PaintView.onDraw(PaintView.java:69)
        at android.view.View.draw(View.java:13712)
        at android.view.View.draw(View.java:13596)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13594)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13594)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13715)
        at android.view.View.draw(View.java:13596)
        at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
        at android.view.View.draw(View.java:13715)

This is my PaintView class:

public class PaintView extends View{
        boolean isEraser = false;
        private Bitmap  mBitmap;
        private Canvas  mCanvas;
        private Path    mPath;
        private Paint   mBitmapPaint;
        private Paint   mPaint;
        private Paint   mPaintScreen;
        int color;
        public PaintView(Context c) {
            super(c);
            mPaintScreen = new Paint();
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(Color.BLACK);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(5);
            color = mPaint.getColor();
            mPath = new Path();

            mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);


        }
        public PaintView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public PaintView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mBitmap = Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            mBitmap.eraseColor(Color.WHITE);
        }
        private float mX =-100, mY = -100;
        Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.background );
        private static final float TOUCH_TOLERANCE = 7;

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(mBitmap,0,0,mPaintScreen);
            canvas.drawPath(mPath, mPaint);
            canvas.drawBitmap(b, 10, 10, mPaint);
        }
        private void touch_start(float x, float y) {
            mPath.reset();
            mPath.moveTo(x, y);
            mX = x;
            mY = y;
        }
        private void touch_move(float x, float y) {
           float dx = Math.abs(x -mX);
           float dy = Math.abs(y - mY);
           if(dx>=TOUCH_TOLERANCE||dy>=TOUCH_TOLERANCE){
               mPath.quadTo(mX,mY, (x+mX)/2, (y+mY)/2);
               mX = x;
               mY = y;
           }
        }
        private void touch_up() {
           mPath.lineTo(mX, mY);
           mCanvas.drawPath(mPath, mPaint);
           mPath.reset();
           mX =-100;
           mY = -100;

        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float x = event.getX();
            float y = event.getY();
            switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                break;
            }
            postInvalidate();
            return true;
            }
        public void setColor(int c){
            if(isEraser)
                mPaint.setColor(Color.WHITE);
            else{
                mPaint.setColor(Color.CYAN);
                //mPaint.setColor(c);
                color = c;
                postInvalidate();
        }
        }
        public float getLineWidth(){
            return mPaint.getStrokeWidth();
        }
        public void setLineWidth(float w){
            mPaint.setStrokeWidth(w);
        }
        public int getDrawingColor(){
            return mPaint.getColor();
        }
        public void clearPaint(){
            mPath.reset();
            mBitmap.eraseColor(Color.WHITE);
            invalidate();
        }
        public void setEraserIcon(){
            b = BitmapFactory.decodeResource(getResources(),R.drawable.eraser );
            color = mPaint.getColor();
            mPaint.setColor(Color.WHITE);
            isEraser = true;
        }
        public void setBrushIcon(){
            b = BitmapFactory.decodeResource(getResources(),R.drawable.brush );
            mPaint.setColor(color);
            isEraser = false;

        }
        public void saveImage(){
            String fileName = "Image" + System.currentTimeMillis();

            ContentValues values = new ContentValues();
            values.put(Images.Media.TITLE,fileName);
            values.put(Images.Media.DATE_ADDED,System.currentTimeMillis());
            values.put(Images.Media.MIME_TYPE,"image/jpeg");

            Uri uri = getContext().getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);
            try{
                OutputStream outStream = getContext().getContentResolver().openOutputStream(uri);
                mBitmap.compress(Bitmap.CompressFormat.JPEG,100, outStream);
                outStream.flush();
                outStream.close();

                Toast message = Toast.makeText(getContext(), R.string.message_saved, Toast.LENGTH_SHORT);
                message.setGravity(Gravity.CENTER, message.getXOffset(),message.getYOffset());
                message.show();

            }catch(Exception ex){
                Toast message = Toast.makeText(getContext(),R.string.message_error_saving, Toast.LENGTH_SHORT);
                message.setGravity(Gravity.CENTER, message.getXOffset()/2,message.getYOffset()/2);
                message.show();
            }
        }
    }`

I created a new Activity and set code like this:

 protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(new PaintView(this));
        }

However when a call my XML which contains PaintView. It get error that I said on above

I'm a newbie in android so thanks you so much to help me!

3
  • 1
    post your logcat. Find where the error occurs. Find out what's null. Fix it. Commented Jun 17, 2013 at 4:40
  • You have an error in this line, Bitmap b = BitmapFactory.decodeResource(getResources(),R.drawable.background );. Put the initialization in constructor Commented Jun 17, 2013 at 4:51
  • The null is in onDraw method. Now I fixed it. Thanks you! Commented Jun 17, 2013 at 7:41

1 Answer 1

3

Try to add initialization code inside public PaintView(Context context, AttributeSet attrs) constructor. So it will look like:

   public PaintView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintScreen = new Paint();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(5);
        color = mPaint.getColor();
        mPath = new Path();

        mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}

and call not setContentView(new PaintView(this)); but setContentView(your.xml); where is your View as a tag.

You got NullPointerException cause you didn't initialize correctly your custom View. When you create your View in XML file, YourView(Context context, AttributeSet attrs) constructor is called.

When you create your View dynamically by using YourView view = new YourView(this)' - 'YourView(Context context) is called.

To prevent this you can create little method with initialization inside, where you will initialize your components, and then call this method from each constructor.

When you want to set dynamically some other values to your drawing you need to call invalidate(); after every changes.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks you so much friend! Your help is really usefull. It's work for me! I added public PaintView(Context context, AttributeSet attrs) contructor and the problem was gone! Thanks!
The answer is not "useful" -- even though may be correct. A "useful" answer would not just provide the fix, but also explain what was wrong and why the specific fix was necessary.
@Procurares i'm sorry! This is my mistake! I got a problem with my acc! By the way, I get another problem about set and get method in my custom view. As you can see, I had some method to change my Paint color, line width,etc. But it also return NullExeption when I call it in my Activity. For example, using like paintView.setLineWidth doesn't work. However some method such as onDraw or onTouchEvent are still working well. Please give me some advice! Thanks!
@323go Thanks for your opinion! That's really interested!
@user2239952, each time when you set some different values for paint, you need to call invalidate(); for example after mPaint.setStrokeWidth(w); call invalidate();
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.