javaandroidperformanceandroid-profiler

Android modify code to make profiler memory chart looks smooth


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:

enter image description here

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;
    }
}

Solution

  • 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:

        public void draw(Canvas canvas) {
            Rect rect = new Rect(0, 0, 300, 300);
            canvas.drawBitmap(getCurrentMoveBitmap(), null, rect, null);
        }