I have custom view which draws bitmaps on canvas. I want to improve my code so the memory chart in profiler looks smooth. I want to know why there are such leaps and GC removing objects every few second. It's worth mentioning that if I remove characterCreator.draw(canvas);
from draw() method then the chart is smooth. Here is how my chart looks like now:
And now the important code:
CharacterCreatorView.java
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if(characterCreator != null)
characterCreator.draw(canvas);
invalidate();
}
CharacterCreator.java
private static final int ROW_BOTTOM_TO_TOP = 8;
private static final int ROW_RIGHT_TO_LEFT = 9;
private static final int ROW_TOP_TO_BOTTOM = 10;
private static final int ROW_LEFT_TO_RIGHT = 11;
private static final int COL_COUNT = 13;
private static final int ROW_COUNT = 21;
private final Bitmap[] leftToRights;
private final Bitmap[] rightToLefts;
private final Bitmap[] topToBottoms;
private final Bitmap[] bottomToTops;
public CharacterCreator(Bitmap baseSprite) {
this.image = baseSprite;
this.widthAllCols = image.getWidth();
this.heightAllRows = image.getHeight();
this.widthOneFrame = this.widthAllCols / 13;
this.heightOneFrame = this.heightAllRows / ROW_COUNT;
this.topToBottoms = new Bitmap[COL_COUNT];
this.rightToLefts = new Bitmap[COL_COUNT];
this.leftToRights = new Bitmap[COL_COUNT];
this.bottomToTops = new Bitmap[COL_COUNT];
imageResized = Bitmap.createScaledBitmap(getMoveBitmaps()[0], 300, 300, false);
}
(...)
public void draw(Canvas canvas) {
imageResized = Bitmap.createScaledBitmap(getCurrentMoveBitmap(), 300, 300, false);
// canvas.drawBitmap(imageResized, 0, 0, null);
}
public Bitmap getCurrentMoveBitmap() {
Bitmap[] bitmaps = this.getMoveBitmaps();
return bitmaps[this.colUsing];
}
public Bitmap[] getMoveBitmaps() {
switch (rowUsing) {
case ROW_BOTTOM_TO_TOP:
return this.bottomToTops;
case ROW_RIGHT_TO_LEFT:
return this.rightToLefts;
case ROW_TOP_TO_BOTTOM:
return this.topToBottoms;
case ROW_LEFT_TO_RIGHT:
return this.leftToRights;
default:
return null;
}
}
You are creating a new bitmap and allocating new memory for it every time you call Bitmap#createScaledBitmap
inside CharacterCreator#draw
. Reassigning imageResized
makes previously stored bitmap available for GC, so it gets collected in the next GC wave. You have basically two options for improving:
imageResized
somewhere else, then create new bitmap only when your getCurrentMoveBitmap()
changed. If possible, do it outside of draw
function, as it causes jank.imageResized
just for drawing, then draw your bitmap directly using Canvas#drawBitmap(Bitmap,Rect,Rect,Paint)
. It avoids memory allocations completely. You can do it like this: public void draw(Canvas canvas) {
Rect rect = new Rect(0, 0, 300, 300);
canvas.drawBitmap(getCurrentMoveBitmap(), null, rect, null);
}