I'm developing a live wallpaper app which will draw an analog clock. So far I reached the point 开发者_高级运维where I draw a clock using three bitmaps: dial, hour hand, minute hand.
When I draw hours and minutes I do it like this (pseudo code):
// without this it looks weird after rotate
Paint smoothPaint = new Paint(FILTER_BITMAP_FLAG);
canvas.drawBitmap(dialBitmap, 0, 0, null);
canvas.rotate(ANGLE_FOR_HOUR_HAND, w/2, h/2);
canvas.drawBitmap(hourBitmap, 0, 0, smoothPaint);
canvas.rotate(ANGLE_FOR_MINUTE_HAND, w/2, h/2);
canvas.drawBitmap(minuteBitmap, 0, 0, smoothPaint);
This works okay except that I'm getting a really low frame rate: about 13 fps. If I turn off bitmap filtering, it increases to about 24 fps, but still low for me.
I know that 2d drawing on Canvas is not accelerated in any way, but still want to ask are there any other options for me to speed up this code? Drawing to bitmap natively somehow? Something else maybe?
Using OpenGL is an option, but its not that simple since LiveWallpapers do not support GL drawing, so I need to use 3rd party hacks (which I know exist) for that which I would rather not do...
"Any other options?" you ask. You have two:
- Don't use bitmaps. The second Cube SDK sample, for example, pops out a rotating 20-line dodecahedron at 25 fps.
- As you've mentioned, you can sometimes use a "hack" for special-purpose graphics within live wallpaper. I suggest you at least take a look at the following three...you may find them useful one day: AndEngine (has a live wallpaper extension), LibGDX (allows you to prototype in a desktop environment; live wallpaper facilities still under development, methinks), and GLWallpaperService (designed specifically to bring GLSurfaceView to live wallpaper).
In your post you say that 24 fps is "still low" for you. It is my understanding that 24 fps is approximately the limit of human perception (it's what Flash uses by default, anyway). I suggest you go no higher, even if you can, in order to preserve battery life.
Edit: One other "hack" to consider: renderscript. That's how some of the sophisticated wallpapers (Galaxy, Grass, Water) that come with many phones work. See renderscript enabling java files here: https://android.googlesource.com/platform/packages/wallpapers/Basic/+/master/src/com/android/wallpaper
How about rendering your hand configuration to an intermediate bitmap each time the minute-hand changes, and then rendering that static bitmap to your canvas on each frame?
Found few things that helped to increase frame rate, will post here as an answer to myself :)
First is to use Canvas.drawBitmap(Bitmap, Matrix, Paint) overload to supply the matrix, instead of using canvas.save() + canvas.rotate() + canvas.restore() - more efficient.
Second: reducing the size of bitmaps. Earlier they were padded to near screen-size of hdpi (480pix) with transparent pixels added around them. After I cropped these transparent pixels away and modified the rendering code to account for that, rotating became much more efficient (as expected).
精彩评论