Speed up your Android UI

Some Android applications require to squeeze every bit of performance out of the UI toolkit and there are many ways to do so. In this article, you will discover how to speed up the drawing and the perceived startup time of your activities. Both these techniques rely on a single feature, the window’s background drawable.

The term window background is a bit misleading however. When you setup your user interface by calling setContentView() on an Activity, Android adds your views to the Activity‘s window. The window however does not contain only your views, but a few others created for you. The most important one is, in the current implementation used on the T-Mobile G1, the DecorView, highlighted in the view hierarchy below:

A typical Android view hierarchy

The DecorView is the view that actually holds the window’s background drawable. Calling getWindow().setBackgroundDrawable() from your Activity changes the background of the window by changing the DecorView‘s background drawable. As mentioned before, this setup is very specific to the current implementation of Android and can change in a future version or even on another device.

If you are using the standard Android themes, a default background drawable is set on your activities. The standard theme currently used on the T-Mobile G1 uses for instance a ColorDrawable. For most applications, this background drawable works just fine and can be left alone. It can however impacts your application’s drawing performance. Let’s take the example of an application that always draws a full screen opaque picture:

An opaque user interface doesn't need a window background

You can see on this screenshot that the window’s background is invisible, entirely covered by an ImageView. This application is setup to redraw as fast as it can and draws at about 44 frames per second, or 22 milliseconds per frame (note: the number of frames per second used in this article were obtained on a T-Mobile G1 with my finger on the screen so as to reduce the drawing speed which would otherwise be capped at 60 fps.) An easy way to make such an application draw faster is to remove the background drawable. Since the user interface is entirely opaque, drawing the background is simply wasteful. Removing the background improves the performance quite nicely:

Remove the background for faster drawing

In this new version of the application, the drawing speed went up to 51 frames per second, or 19 milliseconds per frame. The difference of 3 milliseconds per is easily explained by the speed of the memory bus on the T-Mobile G1: it is exactly the time it takes to move the equivalent of a screenful of pixels on the bus. The difference could be even greater if the default background was using a more expensive drawable.

Removing the window’s background can be achieved very easily by using a custom theme. To do so, first create a file called res/values/theme.xml containing the following:

<resources>
    <style name="Theme.NoBackground" parent="android:Theme">
        <item name="android:windowBackground">@null</item>
    </style>
</resources>

You then need to apply the theme to your activity by adding the attribute android:theme="@style/Theme.NoBackground" to your <activity /> or <application /> tag. This trick comes in very handy for any app that uses a MapView, a WebView or any other full screen opaque view.

Opaque views and Android: this optimization is currently necessary because the Android UI toolkit is not smart enough to prevent the drawing of views hidden by opaque children. The main reason why this optimization was not implemented is simply because there are usually very few opaque views in Android applications. This is however something that I definitely plan on implementing as soon as possible and I can only apologize for not having been able to do this earlier.

Using a theme to change the window’s background is also a fantastic way to improve the perceived startup performance of some of your activities. This particular trick can only be applied to activities that use a custom background, like a texture or a logo. The Shelves application is a good example:

Textured backgrounds are good candidates for window's background

If this application simply set the wooden background in the XML layout or in onCreate() the user would see the application startup with the default theme and its dark background. The wooden texture would only appear after the inflation of the content view and the first layout/drawing pass. This causes a jarring effect and gives the user the impression that the application takes time to load (which can actually be the case.) Instead, the application defines the wooden background in a theme, picked up by the system as soon as the application starts. The user never sees the default theme and gets the impression that the application is up and running right away. To limit the memory and disk usage, the background is a tiled texture defined in res/drawable/background_shelf.xml:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/shelf_panel"
    android:tileMode="repeat" />

This drawable is simply referenced by the theme:

<resources>
    <style name="Theme.Shelves" parent="android:Theme">
        <item name="android:windowBackground">@drawable/background_shelf</item>
        <item name="android:windowNoTitle">true</item>
    </style>
</resources>

The same exact trick is used in the Google Maps application that ships with the T-Mobile G1. When the application is launched, the user immediately sees the loading tiles of MapView. This is only a trick, the theme is simply using a tiled background that looks exactly like the loading tiles of MapView.

Sometimes the best tricks are also the simplest so the next time you create an activity with an opaque UI or a custom background, remember to change the window’s background.

Download the source code of the first example.

Download the source code of Shelves.

23 Responses to “Speed up your Android UI”

  1. Raj says:

    Does the No background setting in xml styles improve applications which use fullscreen theme also ? Like full screen games ??

  2. Chris says:

    Yes It does.. that is clearly mentioned in the article

  3. Timmy says:

    Chris I didn’t notice it either until I saw your post actually :)

  4. Is this optimization relevant when using a SurfaceView, or does the SurfaceView magic shortcut the window background drawing?

  5. Romain Guy says:

    It may or may not be relevant. SurfaceView basically drills a hole through the activity window and puts a second window behind it. If you only draw the SurfaceView, there’s no need to worry about the window background. However, if you somehow invalidate() the SurfaceView or any other view in the activity’s window, then yes, it’s worth it.

  6. I see; thanks for the reply!

  7. Pop says:

    haha, keep the tweaking flowing!

  8. Luke says:

    “The main reason why this optimization was not implemented is simply because there are usually very few opaque views in Android applications.”

    Don’t most apps completely cover the background with an opaque view? Am I missing something here?

  9. Romain Guy says:

    No they don’t. No Android widget is opaque by default. A ListView is totally transparent for instance.

  10. Luke says:

    So every app on the system is taking a performance hit to draw a black background and then overlay translucent controls? Why not just make the list view white text on a black background and not mess with transparency unless explicitly requested?

  11. Romain Guy says:

    Because a ListView can contain anything and not just text and then it you would have to either make sure all the views you put in your ListView are opaque or the ListView itself would be opaque in which case it would be useless if your widgets are themselves opaque.

    Besides, if ListView was opaque, there would still be blending between the list and its control. So in the end there would be no difference.

  12. Greg Krimer says:

    Hey Romain, just wanted to say thanks for this and the many other excellent articles you have posted on the Android Blog. My coworkers and I have found them extremely valuable. Keep up the great work! (Also thanks for your consistent help on the newsgroup. It is much appreciated!)

  13. Romain Guy says:

    Hi Greg,

    Glad to see it’s useful!

  14. Ddorid says:

    Very useful stuf. Can you write tutorial for transparent activity ?

  15. Greg Tong says:

    Romain, we exchanged email privately where you told me that code you publish is licensed under Apache 2.0.

    Since we want to re-use this code, can you please make the licensing explicit in your posts? You need to display the Apache 2.0 license notice.

    Thanks.

  16. Federico says:

    Hi Romain,

    I tried running your WindowBackground project on my phone (Motorola Milestone running Android 2.0) and I get only 15 fps. Tried setting the minSdkVersion to 5, 4, and 3 and they all produce similar results.

    I also noticed that if I create an activity with nothing but a SurfaceView, it will take on average 21ms per frame, without any actual drawing on the canvas (not even drawing a solid color).

    Is this normal? Is it a bug in 2.0 that has been fixed in 2.0.1? Or is it some problem with the phone itself?

    Thanks.

  17. Sebastian says:

    Just tested the code on the Nexus One and obtained only 33fps without touch and 28fps with touch. Am I doing something wrong?

  18. Damn, awesome website. I actually came across this on Yahoo, and I am happy I did. I will definately be returning here more often. Wish I could add to the conversation and bring a bit more to the table, but am just absorbing as much info as I can at the moment.

    Thank You

    Mobile Phones Deals

  19. Nils says:

    What kind of file is “The source code of the first example”?
    I think I need it because I got:
    [2010-09-06 07:00:58 – com.android.ide.eclipse.adt.internal.project.AndroidManifestParser] Parser exception for /MyProject/AndroidManifest.xml: Attribute “theme” bound to namespace “http://schemas.android.com/apk/res/android” was already specified for element “activity”.

  20. dekorasyon says:

    A ListView is totally transparent for instance..

  21. jraanamo says:

    Hi,

    I know this is a little of the topic but has to do with ListView and performance and I know that you Roman have the answer already :)

    I have a ListView that displays different views depending on what is the content of the current record in the underlying Cursor (MergeCursor actually). The layout on each row is a little complex and I would normally use ViewHolder for this.

    The question is: how can I use ListView’s caching with different types of items and avoid creating a new view each time Adapter.getView is called? I tried using CursorAdapter with newView and bindView but naturally bindView may be called with a view of type that was not intended for the current cursor row.