Can't draw dashed line in Android with hardware acceleration

Can't draw dashed line in Android with hardware acceleration

Okay, today I want to share with you a bug which I had faced about three times in my development. We all know Android use skia as its graphics backend. And that was the reason for a little funny bug when we draw a line in Android’s Canvas.

We will look into a piece of code which will draw a line into a canvas from (0, 0) to (100, 0). We use a basic paint object, black, straight and has a 2.0f thickness.

canvas.drawLine(0, 0, 100, 0, paint);

That was straightforward:

[![line](/content/images/2015/07/line.png)](/content/images/2015/07/line.png)

We will try to draw it as dashed. Apply PathEffect for paint:

paint.setPathEffect(new DashPathEffect(new float[] { 5, 2, 2 }, 0));
canvas.drawLine(0, 0, 100, 0, paint);
[![empty1](/content/images/2015/07/empty1.png)](/content/images/2015/07/empty1.png)

Result seems to be okay. But now, in real application, performance should be a hit. We will use hardware acceleration to significant increase our app’s performance (espcially with drawing app).

android:hardwareAccelerated="true"

And this is result. What the hell?

[![line](/content/images/2015/07/line.png)](/content/images/2015/07/line.png)

No dash anymore. What happened?

The answer is: Android bug

That was crazy. When hardware acceleration is activated, Android has changed its graphics pipeline when rendering which lead to this bug. We can’t simply draw dashed line as we wish.

How can we fix this?

We have two ways to fix this bug:

  • Turn off hardware acceleration
  • Don’t use Canvas.drawLine()

Case 1: ofc we will not turn off hardware acceleration in global scope. We will turn off it only in the view which Canvas is dealing with:

public static void disableHardwareRendering(View v) {
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
    v.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  }
}

Case 2: don’t use Canvas.drawLine(), we will create a Path object from start point to end point, and use Canvas.drawPath() after all:

Path baseline = new Path();
baseline.moveTo(0, 0);
baseline.lineTo(100, 0);
canvas.drawPath(baseline, paint);

Now it turns into dashed like before:

[![empty1](/content/images/2015/07/empty1.png)](/content/images/2015/07/empty1.png)

And this is it, wish you never have to look into this issue. Have a good day!