Android Canvas locking throws IllegalArgumentException
Asked Answered
D

1

14

I am trying to implement my own custom SurfaceView that, when touched, draws a circle at the point where the user touched the screen. However, when I call mSurfaceHolder.lockCanvas() I get an exception. Something along the lines of an illegal argument whenever the canvas locks. Sample code is posted below.

public class TapArea extends SurfaceView implements SurfaceHolder.Callback {
    private static final int TAP_RADIUS = 4;
    private boolean mLoaded = false;
    private Paint mTapPaint;
    private SurfaceHolder mSurfaceHolder;

    protected OnTouchListener mTouchEvent = new OnTouchListener() {
        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {
            if (!mLoaded)
                return false;

            Canvas c = null;
            c = mSurfaceHolder.lockCanvas();
            drawTap(c, arg1);

            return true;
        }
    };

    public TapArea(Context context, AttributeSet attrs) {
        super(context, attrs);

        this.setOnTouchListener(mTouchEvent);
        mHandler = new Handler();
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        mTapPaint = new Paint();
    }

    public void drawTap(Canvas canvas, MotionEvent tap) {
        canvas.drawCircle(tap.getX(), tap.getY(), TAP_RADIUS, mTapPaint);
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        // TODO Auto-generated method stub
        mLoaded = true;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        // TODO Auto-generated method stub

    }
}

Below are the error logs I keep getting:

01-17 00:19:44.703: E/Surface(9731): Surface::lock failed, already locked
01-17 00:19:44.796: E/SurfaceHolder(9731): Exception locking surface
01-17 00:19:44.796: E/SurfaceHolder(9731): java.lang.IllegalArgumentException
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.Surface.lockCanvasNative(Native Method)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.Surface.lockCanvas(Surface.java:314)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.SurfaceView$3.internalLockCanvas(SurfaceView.java:762)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.SurfaceView$3.lockCanvas(SurfaceView.java:741)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at com.frequency.FreqTapArea$2.onTouch(FreqTapArea.java:54)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.View.dispatchTouchEvent(View.java:3897)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:869)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1737)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1153)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1721)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2200)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1884)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.os.Handler.dispatchMessage(Handler.java:99)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.os.Looper.loop(Looper.java:130)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at android.app.ActivityThread.main(ActivityThread.java:3835)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at java.lang.reflect.Method.invokeNative(Native Method)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at java.lang.reflect.Method.invoke(Method.java:507)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
01-17 00:19:44.796: E/SurfaceHolder(9731):  at dalvik.system.NativeStart.main(Native Method)

Help would be greatly appreciated.

Distinctive answered 16/1, 2012 at 4:15 Comment(3)
Can you post the error you are getting? I just ran your code without issue in an emulator. Or perhaps post the code/XML where you are trying to instantiate the custom SurfaceView? It should also be noted that your Log statement is misplaced; it will always be called regardless of whether the draw succeeded or not.Chelseachelsey
Hey, I've removed the try/finally blocks and the error still persists and it's not drawing anything on the surface. I've updated the code and added the error log.Distinctive
Your newly posted code doesn't unlock the canvas after drawing (mSurfaceHolder.unlockCanvasAndPost(c) disappeared). Also, mHandler is never declared anywhere.Chelseachelsey
L
10

You need to unlock the canvas after drawing on it. The right secuence is:

  1. get de canvas calling mSurfaceHolder.lockCanvas();
  2. draw on canvas.
  3. unlock canvas calling mSurfaceHolder.unlockCanvasAndPost(c);

In your code could be:

public boolean onTouch(View arg0, MotionEvent arg1) {
        if (!mLoaded)
            return false;

        Canvas c = mSurfaceHolder.lockCanvas();
        drawTap(c, arg1);
        mSurfaceHolder.unlockCanvasAndPost(c);

        return true;
    }
Latty answered 17/1, 2012 at 15:26 Comment(1)
My old code had something like that (should have kept it in the OP), except the lockCanvas() is in a try block and the unlockCanvasAndPost(c) is in a finally block. I will give this code a shot and get back to you.Distinctive

© 2022 - 2024 — McMap. All rights reserved.