Rendering Performance in Android - Overdraw

Written by vishnusosale | Published 2016/09/14
Tech Story Tags: android | performance | overdraw | rendering | ui

TLDRvia the TL;DR App

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, 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.

Detecting and Fixing Overdraw

Fortunately, we can detect overdraws in android phones by selecting “Show overdraw areas” in “Debug GPU overdraw” under “Developer options” in phone settings.

The debug GPU overdraw tool colors the screen with red, green, blue; Red being the areas with highest overdraw and blue being the least overdraw regions of the screen.

In the screenshot attached, I have two LinearLayout vertically oriented. The first LinearLayout has unneeded backgrounds on a few widgets like EditText and ImageView and also on the layout. All the red areas in the image suggests that the views are redrawn on one top of another, therefore contributing to overdraw.

An example of Views being overdrawn

Let’s take a look at the first LinearLayout and figure out what’s wrong.

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/white">

<LinearLayout  
    android:id="@+id/unwanted\_background\_layout"  
    android:layout\_width="match\_parent"  
    android:layout\_height="wrap\_content"  
    **android:background="@color/white"**  
    android:orientation="vertical"  
    android:padding="@dimen/button\_margin">  

    <TextView  
        android:layout\_width="match\_parent"  
        android:layout\_height="wrap\_content"  
        **android:background="@color/grey"**  
        android:padding="8dp"  
        android:text="@string/layout\_with\_unwanted\_backgrounds"  
        android:textSize="17sp" />  

    <ImageView  
        android:id="@+id/image\_view"  
        android:layout\_width="100dp"  
        android:layout\_height="100dp"  
        android:layout\_gravity="center"  
        android:layout\_marginTop="8dp"  
        android:src="@mipmap/ic\_launcher\_round" />  

    <EditText  
        android:layout\_width="match\_parent"  
        android:layout\_height="wrap\_content"  
        android:layout\_gravity="center"  
        android:layout\_marginTop="8dp"  
        android:inputType="text"  
        android:padding="16dp" />  

</LinearLayout>

<LinearLayout  
    ....  
    android:id="@+id/fixed\_background\_layout"  
    ....>  
    ....  
</LinearLayout>

</LinearLayout>

The XML code in bold shows the obvious mistake.

We have declared background colors for each children in the first LinearLayout ViewGroup. We have also set a background color in the parent ViewGroup. Note that setting the background color to the View adds to Overdraw and doesn’t depend on which color is used. Overdraw occurs for same colors and differnt colors too.

First the topmost LinearLayout is drawn on the screen. The background is set to white. The child LinearLayout is drawn next which also have a background color white. The system at this point doesn’t know that the color is the same as before. All it knows is there is new color and the pixels are redrawn again with the new color. The child TextView and ImageView have backgrounds set to each of them which makes the sytem to redraw pixels with new colors. Drawing and redrawing the same pixels wastes GPU cycles. Redrawing on the same pixels with same data that was previously there will prove to be costly for rendering performance.

How do we reduce overdraw and improve performance?

We know that the same color is drawn a multiple times in child views. Let’s get rid of that first as it is not a design constraint.

<LinearLayoutandroid:id=”@+id/fixed_background_layout”android:layout_width=”match_parent”android:layout_height=”wrap_content”android:orientation=”vertical”android:padding=”@dimen/button_margin”>

Getting rid of the white background on the child LinearLayout shows a lot less overdraw -

Reduced overdraw shown by less red marks

If the design allows, you could even remove the background for the TextView and improve the performance.

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.

To increase performance even further, use flat layouts as much as possible. Nesting several instances of Views can be very expensive as the children Views should be measured twice. Since, this is out of scope of this story, you can research on Optimizing Layout Hierarchies in the official Android Developers website.

Clone the Overdraw repo on the GitHub to check out the full code -https://github.com/vishnusosale/Android-Overdraw

Please share if you think this article is super helpful to you or your friends who are Android developers. Your claps helps us to be motivated and write more content.


Published by HackerNoon on 2016/09/14