Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 1 | page.title=Window Backgrounds & UI Speed |
Scott Main | 796ce77 | 2011-02-16 10:04:45 -0800 | [diff] [blame] | 2 | parent.title=Articles |
| 3 | parent.link=../browser.html?tag=article |
Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 4 | @jd:body |
| 5 | |
| 6 | <p>Some Android applications require to squeeze every bit of performance out of |
| 7 | the UI toolkit and there are many ways to do so. In this article, you will |
| 8 | discover how to speed up the drawing and the <em>perceived</em> startup time of |
| 9 | your activities. Both these techniques rely on a single feature, the window's |
| 10 | background drawable.</p> |
| 11 | |
| 12 | <p>The term <em>window background</em> is a bit misleading, however. When you |
| 13 | setup your user interface by calling <code>setContentView()</code> on an |
| 14 | {@link android.app.Activity}, Android adds your views to the <code>Activity</code>'s |
| 15 | window. The window however does not contain only your views, but a few others |
| 16 | created for you. The most important one is, in the current implementation used |
| 17 | on the T-Mobile G1, the <code>DecorView</code>, highlighted in the view |
| 18 | hierarchy below:</p> |
| 19 | |
| 20 | <div style="text-align: center;"><img src="images/window_background_root.png" alt="A typical Android view hierarchy"></div> |
| 21 | |
| 22 | <p>The <code>DecorView</code> is the view that actually holds the |
| 23 | window's background drawable. Calling |
| 24 | {@link android.view.Window#setBackgroundDrawable(android.graphics.drawable.Drawable) getWindow().setBackgroundDrawable()} |
| 25 | from your <code>Activity</code> changes the background of the window by changing |
| 26 | the <code>DecorView</code>'s background drawable. As mentioned before, this |
| 27 | setup is very specific to the current implementation of Android and can change |
| 28 | in a future version or even on another device.</p> |
| 29 | |
| 30 | <p>If you are using the standard Android themes, a default background drawable |
| 31 | is set on your activities. The standard theme currently used on the T-Mobile G1 |
| 32 | uses for instance a {@link android.graphics.drawable.ColorDrawable}. For most |
| 33 | applications, this background drawable works just fine and can be left alone. It |
| 34 | can however impacts your application's drawing performance. Let's take the |
| 35 | example of an application that always draws a full screen opaque picture:</p> |
| 36 | |
| 37 | <div style="text-align: center;"><img src="images/window_background.png" alt="An opaque user interface doesn't need a window background"></div> |
| 38 | |
| 39 | <p>You can see on this screenshot that the window's background is invisible, |
| 40 | entirely covered by an <code>ImageView</code>. This application is setup to |
| 41 | redraw as fast as it can and draws at about 44 frames per second, or 22 |
| 42 | milliseconds per frame (<strong>note:</strong> the number of frames per second |
| 43 | used in this article were obtained on a T-Mobile G1 with my finger on the screen |
| 44 | so as to reduce the drawing speed which would otherwise be capped at 60 fps.) An |
| 45 | easy way to make such an application draw faster is to <em>remove</em> the |
| 46 | background drawable. Since the user interface is entirely opaque, drawing the |
| 47 | background is simply wasteful. Removing the background improves the performance |
| 48 | quite nicely:</p> |
| 49 | |
| 50 | <div style="text-align: center;"><img src="images/window_background_null.png" alt="Remove the background for faster drawing"></div> |
| 51 | |
| 52 | <p>In this new version of the application, the drawing speed went up to 51 |
| 53 | frames per second, or 19 milliseconds per frame. The difference of 3 |
| 54 | milliseconds per is easily explained by the speed of the memory bus on the |
| 55 | T-Mobile G1: it is exactly the time it takes to move the equivalent of a |
| 56 | screenful of pixels on the bus. The difference could be even greater if the |
| 57 | default background was using a more expensive drawable.</p> |
| 58 | |
| 59 | <p>Removing the window's background can be achieved very easily by using |
| 60 | a custom theme. To do so, first create a file called |
| 61 | <code>res/values/theme.xml</code> containing the following:</p> |
| 62 | |
| 63 | <pre class="prettyprint"><resources> |
| 64 | <style name="Theme.NoBackground" parent="android:Theme"> |
| 65 | <item name="android:windowBackground">@null</item> |
| 66 | </style> |
| 67 | </resources></pre> |
| 68 | |
| 69 | <p>You then need to apply the theme to your activity by adding the attribute |
| 70 | <code>android:theme="@style/Theme.NoBackground"</code> to your |
| 71 | <code><activity /></code> or <code><application /></code> tag. This |
| 72 | trick comes in very handy for any app that uses a <code>MapView</code>, a |
| 73 | <code>WebView</code> or any other full screen opaque view.</p> |
| 74 | |
| 75 | <p><strong>Opaque views and Android</strong>: this optimization is currently |
| 76 | necessary because the Android UI toolkit is not smart enough to prevent the |
| 77 | drawing of views hidden by opaque children. The main reason why this |
| 78 | optimization was not implemented is simply because there are usually very few |
| 79 | opaque views in Android applications. This is however something that I |
| 80 | definitely plan on implementing as soon as possible and I can only apologize for |
| 81 | not having been able to do this earlier.</p><p>Using a theme to change the |
| 82 | window's background is also a fantastic way to improve the <em>perceived</em> |
| 83 | startup performance of some of your activities. This particular trick can only |
| 84 | be applied to activities that use a custom background, like a texture or a logo. |
| 85 | The <a href="http://code.google.com/p/shelves">Shelves</a> application is a good |
| 86 | example:</p> |
| 87 | |
| 88 | <div style="text-align: center;"><img src="images/shelves2.png" alt="Textured backgrounds are good candidates for window's background"></div> |
| 89 | |
| 90 | <p>If this application simply set the wooden background in the XML layout or in |
| 91 | <code>onCreate()</code> the user would see the application startup with the |
| 92 | default theme and its dark background. The wooden texture would only appear |
| 93 | after the inflation of the content view and the first layout/drawing pass. This |
| 94 | causes a jarring effect and gives the user the impression that the application |
| 95 | takes time to load (which can actually be the case.) Instead, the application |
| 96 | defines the wooden background in a theme, picked up by the system as soon as the |
| 97 | application starts. The user never sees the default theme and gets the |
| 98 | impression that the application is up and running right away. To limit the |
| 99 | memory and disk usage, the background is a tiled texture defined in |
| 100 | <code>res/drawable/background_shelf.xml</code>:</p> |
| 101 | |
| 102 | <pre class="prettyprint"><bitmap xmlns:android="http://schemas.android.com/apk/res/android" |
| 103 | android:src="@drawable/shelf_panel" |
| 104 | android:tileMode="repeat" /></pre><p>This drawable is simply referenced by the theme:</p> |
| 105 | |
| 106 | <pre class="prettyprint"><resources> |
| 107 | <style name="Theme.Shelves" parent="android:Theme"> |
| 108 | <item name="android:windowBackground">@drawable/background_shelf</item> |
| 109 | <item name="android:windowNoTitle">true</item> |
| 110 | </style> |
| 111 | </resources></pre> |
| 112 | |
| 113 | <p>The same exact trick is used in the <em>Google Maps application that ships |
| 114 | with the T-Mobile G1. When the application is launched, the user immediately |
| 115 | sees the loading tiles of <code>MapView</code>. This is only a trick, the theme |
| 116 | is simply using a tiled background that looks exactly like the loading tiles of |
| 117 | <code>MapView</code>.</em></p> |
| 118 | |
| 119 | <p>Sometimes the best tricks are also the simplest, so the next time you create |
| 120 | an activity with an opaque UI or a custom background, remember to change the |
| 121 | window's background.</p> |
| 122 | |
| 123 | <p><a href="http://progx.org/users/Gfx/android/WindowBackground">Download the source code of the first example</a>.</p> |
| 124 | |
| 125 | <p><a href="http://code.google.com/p/shelves/">Download the source code of Shelves</a>.</p> |
| 126 | |
| 127 | |