0

I have a live wallpaper that is running a looped animation by drawing each frame to the canvas. I have one single image, sized to the exact dimensions of the screen. I have a set of 400 frames sized exactly to fit about the bottom third of the screen; this is where the animation occurs. Here is the code that displays them:

public void updateBG() {
    mHandler.removeCallbacks(mUpdateDisplay);
    if (mVisible) {
        mHandler.postDelayed(mUpdateDisplay, 40);
    }

    if (imagesLoaded < totalFrames) {
        ShowLoadingProgress();
    } else {
        SurfaceHolder holder = getSurfaceHolder();
        Canvas c = null;
        try {
            c = holder.lockCanvas();
            if (c != null) {
                Paint p = new Paint();
                p.setAntiAlias(true);
                c.drawRect(0, 0, c.getWidth(), c.getHeight(), p);
                Rect destinationRect = new Rect();
                destinationRect.set(0, 0, canvasWidth, canvasHeight);


                if (animStartX > 0 || animEndX > 0 || animStartY > 0 || animEndY > 0) {
                    c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[totalFrames], 0, bitmapArray[totalFrames].length), null, destinationRect, p);
                    Rect destinationRectAnim = new Rect();
                    destinationRectAnim.set(animX, animY, animX+animWidth, animY+animHeight);
                    c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[bgcycle], 0, bitmapArray[bgcycle].length), null, destinationRectAnim, p);
                } else {
                    c.drawBitmap(BitmapFactory.decodeByteArray(bitmapArray[bgcycle], 0, bitmapArray[bgcycle].length), null, destinationRect, p);
                }

            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
        bgcycle++;
    }
}

This code is running at approximately 10-12 FPS on an Xperia Ion (dual-core 1.5 GHz cpu) and worse on older devices. It was going much better when I saved entire frames at half the screen resolution. It actually got worse when I started using full frames at the screen resolution (which should have eliminated the need to interpolate on each frame). It then got even worse when I started using this code, which writes two bitmaps (presumably because it can't save the top half of the canvas from the last run).

How can I optimize this? I'd rather not save full frames as just saving the animated part for each frame really reduces memory usage. Something feels really wrong here, especially given that this is running with 3GHz of power behind it. I used to watch movies on a 450 MHz Pentium III. Is there something obvious that I'm doing wrong? Is the phone still trying to interpolate the images even though they are sized correctly?

Nicholas
  • 1,974
  • 4
  • 20
  • 46
  • In the end, after trying a similar app with AndEngine, I decided that the frame-by-frame method will not work for displaying a video. Instead I have decided to move to FFMpeg and hopefully get that up to a reasonable framerate. – Nicholas Aug 30 '13 at 20:43

1 Answers1

3

You are decoding your bitmap on every frame, it's expensive and it will generate garbage that will trigger GCs. You are also rendering using software rendering. Here are your solutions, in order:

  • Don't re-decode the bitmaps on every frame
  • Reuse bitmap objects (see BitmapFactory.Options.inBitmap)
  • Use hardware acceleration (render directly into a View instead of a SurfaceView.) Software interpolation is very expensive.
Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • I'll have to research all of these; I'm still very green in Java/Android development. Could you tell me what you mean by "Don't re-decode on every frame'? I'm storing the images in a byte array as JPEGs which avoids io on each frame, but if I stored them as bmps I would eat up hundreds of MB of memory. Am I misunderstanding? Thanks! – Nicholas Aug 16 '13 at 20:54
  • Also, try not to recreate objects like your `Paint` and `Rect` instances if possible within the loop. I'd seriously consider holding the bitmaps in memory if performance is at all a concern. The bitmap decoding is definitely a huge factor. – kabuko Aug 17 '13 at 00:05
  • Could you direct me to some code samples or tutorials that explain these, especially the difference between view and surfaceView? Google only points me to SO answers, which are often very direct and for more experienced developers. And my books talk about graphics rendering within activities, which I know have some important differences from a live wallpaper. Thanks. – Nicholas Aug 17 '13 at 23:54