Search code examples
androidmemorybitmapframe-rate

Consequences of recycling Bitmaps?


Hi in my application I have an explosion animation that comes up extremely often. when creating an explosion I load 3 images from resources then once the explosion animation is over I recycle those 3 images. I am constantly doing this and have noticed framerate drops. Is their a better way of doing this like static bitmaps or something?


Solution

  • I once made an application, a simple canvas on which bombs exploded. I used a tiled bitmap composed of each step of the explosion and drew only a part of it, which changes often in order to create the animation effect. It updates steps automatically following currentTimestamp

    So this is the explosion class:

    public class ExplosionAnimated {
    
    private static final String TAG = ExplosionAnimated.class.getSimpleName();
    
    private Bitmap mBitmap;
    private Rect mSourceRect;
    private int mFrameCountX;
    private int mFrameCountY;
    private int mCurrentFrame;
    private long mFrameTicker;
    private int mFramePeriod;
    
    private int mSpriteWidth;
    private int mSpriteHeight;
    
    private int mX;
    private int mY;
    
    private boolean mFinished = false;
    
    public ExplosionAnimated(Bitmap pBitmap, int pX, int pY, 
            int pFrameCountX, int pFrameCountY, int pFps) {
    
        this.mBitmap = pBitmap;
        this.mX = pX;
        this.mY = pY;
        this.mCurrentFrame = 0;
        this.mFrameCountX = pFrameCountX;
        this.mFrameCountY = pFrameCountY;
        this.mSpriteWidth = pBitmap.getWidth() / pFrameCountX;
        this.mSpriteHeight = pBitmap.getHeight() / pFrameCountY;
        this.mSourceRect = new Rect(0, 0, this.mSpriteWidth, this.mSpriteHeight);
        this.mFramePeriod = 1000 / pFps;
        this.mFrameTicker = 0l;
    }
    
    public void update(long gameTime) {
    
        if (gameTime > this.mFrameTicker + this.mFramePeriod) {
            this.mFrameTicker = gameTime;
    
            this.mCurrentFrame++;
            if (this.mCurrentFrame >= this.mFramePeriod) {
                this.mCurrentFrame = 0;
                this.mFinished = true;
            }
        }
    
        if (!this.mFinished) {
    
            this.mSourceRect.left = this.mCurrentFrame * this.mSpriteWidth;
            this.mSourceRect.right = this.mSourceRect.left + this.mSpriteWidth;
        }
    }
    
    public void draw(Canvas canvas) {
    
        Rect destRect = new Rect(this.mX, this.mY, 
                this.mX + this.mSpriteWidth, 
                this.mY + this.mSpriteHeight);
        canvas.drawBitmap(this.mBitmap, this.mSourceRect, destRect, null);
    }
    
    public boolean isFinished() {
        return this.mFinished;
    }
    }
    

    These are methods from an object (Bomb.java for exemple) that starts explosion and draw it:

    public void explode(Context pContext, Canvas pCanvas) {
    
        this.mState = State.EXPLODING;
        this.mExplosion = new ExplosionAnimated(this.mExplosionBitmap, 
                (int) this.mX, (int) this.mY, 7, 3, 7);
    }
    
    public void doDraw(Canvas pCanvas) {
    
        if (this.mState == State.EXPLODING) {
    
            if (this.mExplosion.isFinished()) {
                this.mState = State.EXPLODED;
            } else {
                this.mExplosion.update(System.currentTimeMillis());
                this.mExplosion.draw(pCanvas);
            }
        } else {
            pCanvas.drawBitmap(this.mBombBitmap, this.mX, this.mY, null);
        } 
    }
    

    I used a Thread and a SurfaceView to continually draw the bomb (or the explosion), giving just the currentTimestamp to update the explosion.

    I hope it helps, and if you need I can show and explain more code