INTRODUCTION
Rendering performance is one of the most common performance issues that is often neglected while building an Android app. Given the fact that most Android phones run on less powerful CPUs and GPUs, we developers should make sure the app we develop does not overload both the processors with unwanted and/or repetitive instructions.
Both processors work together to render images, colors, drawables, etc. Unnecessary layouts and frequent and/or unnecessary invalidations (Views being measured, torn down and rebuilt or redrawn again, example: List View being rebuilt/redrawn too many times as the user scrolls) result in performance overhead on the CPU. On the GPU, however, one of the major and common performance overhead comes from overdraw
OVERDRAW
Overdraw, as the name suggests, is a term used to describe how many times a pixel on the screen has been redrawn in a single frame. Imagine, painting a room and re-painting it all over again; this results in wasting time and energy to paint the room the first time. With overdraw in Android we waste GPU time by coloring the pixels on the screen that end up being colored again by something else later.
Fortunately, we can detect overdraws in android by selecting "Show overdraw areas" in "Debug GPU overdraw" under "Developer options" in phone settings.
An example of Views being overdrawn is shown in the picture below.
All the red areas in the image suggests that the views are redrawn on one top of another. More the intensity of red, more is the overdraw. Let's take a look at the code and figure out what's wrong.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white">
<ImageView
android:id="@+id/androidImageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@mipmap/ic_launcher" />
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/userProfilePicLeaderBoard"
android:layout_toStartOf="@+id/androidVersion"
android:background="@android:color/white"
android:orientation="horizontal"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:id="@+id/androidName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="My Name is Android Marshmallow"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<TextView
android:id="@+id/androidVersion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@android:color/white"
android:padding="5dp"
android:text="v6.0"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
Without most of the boiler plate code, we have a parent RelativeLayout which has a android:background="@android:color/white"
, a child LinearLayout with a android:background="@android:color/white"
and another child TextView with android:background="@android:color/white"
Now it is very important that you notice white color is being used multiple times in the code. First the RelativeLayout is drawn with the white background, then the child LinearLayout also draws a white color and the TextView draws white again. Therefore, we are wasting GPU cycles here by redrawing on the same pixels multiple times. Note that this is not because the colors are same, but because we are redrawing the pixels again and again.
How do we remove overdraw and improve performance?
We now know that the color white is being drawn multiple times on the same view. All we have to do is to remove android:background="@android:color/white"
in LinearLayout and TextView.
After changes in the code the overdraw is much lesser as shown in the image below
Now the red marks are invisible suggesting that there's very less or nil overdraw. This view is more faster to render by the GPU, less time consumed and helps overall user experience to be much more smoother and faster.