On Android, there are a few different overloads for the drawBitmap method. One of these methods takes an integer color array and draws it as a bitmap:
The documentation states that "this method avoids explicitly creating a bitmap object which can be more efficient if the colors are changing often". While it's true that a bitmap object isn't created, the design of this method makes it a poor choice for drawing, as you'll see below.
public void drawBitmap (int colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint)
First, some background. Within PixStack, I use the fantastic FreeImage library to load and save images. Once an image has been loaded, the pixel data is transformed, and is stored internally in ARGB format. Up until very recently, the pixels were then kept in an integer array. That worked great, because it's possible to draw a color array using the above method, and because I could very easily access the pixel data directly, which becomes important when the images are large.
Images were slow to draw, but I had assumed that was mostly down to the fact that I was asking Android to draw a large number of pixels with scaling. After looking at some other photo editors a few weeks back, I found that for the same image, drawing peformance was much worse in my app than in others. With a few basic tests, I confirmed that drawing a bitmap object was far faster than drawing a color array. Constantly curious, I dove into the Android source code to find out why.
The following is what takes place when you draw a bitmap object:
Checks that the bitmap hasn't been recycled, beore simply handing control off to native_drawBitmap.
native_drawBitmap is translated into drawBitmap__BitmapFFPaint, which sets up the (native) canvas and paint objects, before calling into the Skia library.
Does some bounds checks, then calls an internal draw method.
Does some minor work, before calling another internal method.
From what I understand, this is the point at which the bitmap is actually drawn on screen by the device. How it's drawn isn't relevant here, so for all intents and purposes, this is the last call when drawing.
Here's what happens when you draw a color array:
Performs some sanity checks on its arguments, before calling an overloaded version of native_drawBitmap.
As before, native_drawBitmap is translated into another native method, in this case drawBitmapArray. Unlike the equivalent method above, this method allocates a new Skia bitmap (SkBitmap) and copies the pixels into it. The copy is done row-by-row, and it is at this point that the pixels are pre-multiplied. From here, the call structure is the same as the case above.
The reduced performance seen when using a color array comes down to the fact that every time you draw, the system will initialise a new native SkBitmap object. This isn't a problem when drawing a (Java) bitmap object, since the SkBitmap is initialised once, in the bitmap constructor.
If you have the option, always stick with drawing a bitmap object.