One of the recommendations we have been giving during these last chapters is to avoid allocating objects in the onDraw() method. But what will happen if we start allocating objects?
Let's create a simple custom view and allocate an object on purpose so we can evaluate the result when running the app:
package com.packt.rrafols.draw; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.Region; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; public class PerformanceExample extends View { private static final String TAG =PerformanceExample.class.
getName(); private static final int BLACK_COLOR = 0xff000000; private static final int WHITE_COLOR = 0xffffffff; private float angle; public PerformanceExample(Context context, AttributeSet attributeSet)
{ super(context, attributeSet); angle = 0.f; } /** * This is precisely an example of what MUST be avoided. * It is just to exemplify chapter 7. * * DO NOT USE. * * @param canvas */ @Override protected void onDraw(Canvas canvas) { Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Rect rect = new Rect(0, 0, getWidth(), getHeight()); Paint paint = new Paint(); paint.setColor(BLACK_COLOR); paint.setStyle(Paint.Style.FILL); canvas.drawRect(rect, paint); canvas.save(); canvas.rotate(angle, getWidth() / 2, getHeight() / 2); canvas.translate((getWidth() - getWidth()/4) / 2, (getHeight() - getHeight()/4) / 2); rect = new Rect(0, 0, getWidth() / 4, getHeight() / 4); paint = new Paint(); paint.setColor(WHITE_COLOR); paint.setStyle(Paint.Style.FILL); canvas.drawBitmap(bitmap, 0, 0, paint); canvas.drawRect(rect, paint); canvas.restore(); invalidate(); bitmap.recycle(); angle += 0.1f; } }
In this quick example, we are allocating several things within the onDraw() method, from the Paint objects, to the Rect objects, to creating a new bitmap, which allocates internal memory.
If we run this code, we'll get a rotating white rectangle in the middle of the screen, as in the following screenshot:
![](assets/cfb6fc4b-3ea8-44da-a6a3-1fb33a15e297.png)
In addition, we will not only get a similar view. If we check the logcat logs when our application is running, we might get lines similar to these:
I art : Starting a blocking GC Explicit
I art : Explicit concurrent mark sweep GC freed 198893(13MB) AllocSpace objects, 30(656KB) LOS objects, 26% free, 43MB/59MB, paused 2.835ms total 313.353ms
I art : Background partial concurrent mark sweep GC freed 26718(2MB) AllocSpace objects, 1(20KB) LOS objects, 27% free, 43MB/59MB, paused 3.434ms total 291.430ms
We might even get them several times during the application execution. This is the Android run-time's (ART's) garbage collector kicking in to clean unused objects to free up some memory. As we are continuously creating new objects, the VM triggers the garbage collector to free up some memory.
More information about garbage collection can be found at the following URL:
https://en.wikipedia.org/wiki/Garbage_collection_(computer_science).
Luckily, Android Studio already shows us, quite clearly, that we are doing something wrong inside our onDraw() method:
![](assets/086755ce-57d4-42e6-8888-aa6a6a597b59.png)
It also shows us what it might cause if we don't follow this recommendation. In this case, if the garbage collector kicks in, in the middle of a scroll or drawing, we might get some stuttering or, simply, a smooth animation might be seen as jumpy or not as smooth as it should be.
Check the full source code of this example, which shouldn't be followed, in the Example30-Performance folder in the GitHub repository. Please use it as an example of what should be avoided.