• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Drawing very slow with Canvas and SurfaceView

Hello everybody,

I have created an Android 5.1 application with which I can write with a stylus on a tablet using SurfaceView and Canvas. You can find my code below. Unfortunately, the writing is very slow, especially when lot of text is written it starts getting slow. I think the problem is that it is rendered in software. Of course, a possibility to speedup would be to use OpenGL but I don't know it and I think this has a too steep learning curve for me right now.

Nevertheless, is there a possibility to speedup my code (i.e. to make it more responsible when writing)? Or else is it easy to change my code to OpenGL?

Code:
    public class DrawingView extends SurfaceView implements OnTouchListener {
        private Bitmap mBitmap;
        private Canvas m_Canvas;
        private Path m_Path;
        private Paint m_Paint;
        private ArrayList<Pair<Path, Paint>> paths = new ArrayList<>();
        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;
        private boolean isEraserActive = false;
        private int pathCount = 0;
        private View rectangleView;
   
        public DrawingView(Context context, AttributeSet attr) {
            super(context, attr);
   
            setFocusable(true);
            setFocusableInTouchMode(true);
            setBackgroundColor(Color.TRANSPARENT);
            this.setOnTouchListener(this);
            onCanvasInitialization();
            setAlpha(0.99f);
        }
   
        public void onCanvasInitialization() {
            m_Paint = new Paint();
            m_Paint.setAntiAlias(true);
            m_Paint.setDither(true);
            m_Paint.setColor(Color.parseColor("#000000"));
            m_Paint.setStyle(Paint.Style.STROKE);
            m_Paint.setStrokeJoin(Paint.Join.ROUND);
            m_Paint.setStrokeCap(Paint.Cap.ROUND);
            m_Paint.setStrokeWidth(2);
   
            m_Path = new Path();
            Paint newPaint = new Paint(m_Paint);
            paths.add(new Pair<>(m_Path, newPaint));
        }
   
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
   
            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
            m_Canvas = new Canvas(mBitmap);
        }
   
        @Override
        public boolean onTouch(View arg0, MotionEvent event) {
            float x = event.getX();
            float y = event.getY();
   
            if (rectangleView != null) {
                ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) rectangleView.getLayoutParams();
                params.leftMargin = (int) x;
                params.topMargin = (int) y;
                rectangleView.setLayoutParams(params);
                return true;
            } else {
                if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) {
                    isEraserActive = true;
                } else {
                    isEraserActive = false;
                }
   
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        touch_start(x, y);
                        invalidate();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        touch_move(x, y);
                        invalidate();
                        break;
                    case MotionEvent.ACTION_UP:
                        touch_up();
                        invalidate();
                        break;
                }
                return true;
            }
        }
   
        @Override
        protected void onDraw(Canvas canvas) {
            for (Pair<Path, Paint> p : paths) {
                canvas.drawPath(p.first, p.second);
            }
        }
   
        private void touch_start(float x, float y) {
            if (isEraserActive) {
                m_Paint.setStrokeWidth(20);
                m_Paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                Paint newPaint = new Paint(m_Paint);
                paths.add(new Pair<>(m_Path, newPaint));
            } else {
                m_Paint.setColor(Color.BLACK);
                m_Paint.setStrokeWidth(2);
                m_Paint.setXfermode(null);
                Paint newPaint = new Paint(m_Paint);
                paths.add(new Pair<>(m_Path, newPaint));
                pathCount++;
            }
   
            m_Path.reset();
            m_Path.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) {
                m_Path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
                mX = x;
                mY = y;
            }
        }
   
        private void touch_up() {
            m_Path.lineTo(mX, mY);
            m_Canvas.drawPath(m_Path, m_Paint);
            m_Path = new Path();
            Paint newPaint = new Paint(m_Paint);
            paths.add(new Pair<>(m_Path, newPaint));
        }
   
        public void reset() {
            for (Pair<Path, Paint> p : paths) {
                p.first.reset();
            }
            paths.clear();
            pathCount = 0;
            mBitmap.eraseColor(Color.TRANSPARENT);
            invalidate();
        }
    }
 
Back
Top Bottom