Java – Draw to Canvas

Draw to Canvas… here is a solution to the problem.

Draw to Canvas

I’m writing an android app that draws directly to Canvas on the onDraw event of the View.

I’m drawing something that involves drawing each pixel individually, for this I’m using something like :

for (int x = 0; x < xMax; x++) {
  for (int y = 0; y < yMax; y++){
    MyColour = CalculateMyPoint(x, y);
    canvas.drawPoint(x, y, MyColour);
  }
}

The problem here is that this takes a long time to draw because the CalculateMyPoint routine is a very expensive method.

Is there a more efficient way to paint on Canvas, for example, should I draw a bitmap and then draw the entire bitmap onto Canvas on the onDraw event? Or evaluate my colors and fill an array that the onDraw method can use to draw the Canvas?

Users of my app will be able to change parameters that affect drawing on Canvas. At the moment this is very slow.

Solution

As people have pointed out, if CalculateMyPixel() is expensive, calling 150,000 (HVGA) or 384,00 (WVGA) will only kill you.

Best of all, trying to draw your UI as a single pixel via canvas.drawPoint() every time there is an update is almost the least efficient way to do this.

If you’re drawing a single pixel, you almost certainly want some sort of off-screen bitmap that contains pixels, and you can draw it with a simple Canvas.drawBitmap().

You can then decide the best way to manage that bitmap. The easiest way to do this is to make a bitmap object of the desired size and then populate it using the API there.

Alternatively, there is a drawBitmap() version that takes a raw integer array, so you can simply fill it with any value you want, avoiding calling methods for each pixel.

Now you can move pixel computing out of the onDraw() method, which needs to be fast to have a responsive UI and fill in pixels elsewhere. Maybe you count them once at initialization. Maybe you compute them and make selective updates only to the parts that changed before calling invalidate() (e.g. the pixels of (0,0)-(10,l0) changed, so get the current bitmap and modify the region).

Also, now that you have pixels in your bitmap, you can do tricks such as shrinking the size of the bitmap and scaling it when drawing to the screen, so you can spend less time updating those pixels while still filling the entire UI (albeit with a lower resolution).

Related Problems and Solutions