• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Faster Screen Orientation Change
2@jd:body
3
4
5<div id="qv-wrapper">
6<div id="qv">
7
8  <h2>See also</h2>
9  <ol>
10    <li><a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime
11Changes</a></li>
12  </ol>
13
14</div>
15</div>
16
17<p>Android is designed to run efficiently on a wide
18array of devices, with very different hardware configurations. Some
19devices, like the T-Mobile G1, can change their hardware configuration
20at runtime. For instance, when you open the keyboard, the screen change
21from the portrait orientation to the landscape orientation.
22
23<div class="sidebox-wrapper">
24<div class="sidebox">
25<h2>Using the alternate resources framework</h2>
26
27<p>The platform's support for loading orientation-specific
28resources at run time is based on the alternate resources framework.</p>
29
30<p>Providing orientation-specific resources is an important part of
31developing your app. If you are not familiar with resource directory qualifiers
32or how the platform uses them, please read
33<a href="{@docRoot}guide/topics/resources/resources-i18n.html#AlternateResources">
34Alternate Resources</a>.
35</div>
36</div>
37
38<p>To make
39Android app development easier, the Android system automatically handles
40configuration change events and restarts the current activity with the new
41configuration. This is the default behavior that lets you declare
42resources like layouts and drawables based on the orientation, screen
43size, locale, etc. </p>
44
45<p>While this behavior is really powerful, since your application adapts
46automatically to the device's configuration at runtime, it is sometimes
47confusing for new Android developers, who wonder why their activity is
48destroyed and recreated. </p>
49
50<p>Facing this "issue," some developers choose to handle configuration changes
51themselves which is, in general, a short-term solution that will only complicate
52their lives later. On the other hand, the system's automatic resource handling
53is a very efficient and easy way to adapt an application's user interface to
54various devices and devices configurations. It sometimes comes at a price,
55though.</p>
56
57<p>When your application displays a lot of data, or data that is expensive to fetch,
58the automatic destruction/creation of the activities can be lead to a
59painful user experience. Take the example of <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/">Photostream</a>,
60a simple Flickr browsing application. After you launch the application and choose a Flickr account, the
61application downloads a set of 6 photos (on a T-Mobile G1) from the
62Flickr servers and displays them on screen. To improve the user
63experience, the application uses slightly different layouts and drawables in
64portrait and landscape modes and this is what the result looks like:</p>
65
66<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9l0GmPwgCzk/SZoGyJyg6-I/AAAAAAAAACU/ItuVwhegPb8/s1600-h/photostream_landscape.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 214px;" src="images/photostream_landscape.png" alt="" id="BLOGGER_PHOTO_ID_5303558969873198050" border="0"></a></p>
67
68<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9l0GmPwgCzk/SZoGx4I-QlI/AAAAAAAAACM/-GkZR5MUKhY/s1600-h/photostream_portrait.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 214px; height: 320px;" src="images/photostream_portrait.png" alt="" id="BLOGGER_PHOTO_ID_5303558965135557202" border="0"></a></p>
69
70<p>Photostream lets Android take care of the configuration change when the
71screen is rotated. However, can you imagine how painful it would be for the user
72to see all the images being downloaded again? The obvious solution to this
73problem is to temporarily cache the images. They could be cached on the SD card
74(if there's one), in the Application object, in a static field, etc. None of
75these techniques is adapted to the current situation: why should we bother
76caching the images when the screen is not rotated? Fortunately for us, Android
77offers a great API exactly for that purpose.</p>
78
79<p>The Activity class has a special method called
80{@link android.app.Activity#onRetainNonConfigurationInstance()}. This method
81can be used to pass an arbitrary object <em>your future self</em> and Android
82is smart enough to call this method only when needed. In the case of Photostream,
83the application <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#226">used this method</a>
84to pass the downloaded images to the future activity on orientation change.
85The implementation can be summarized like so:</p>
86
87<pre class="prettyprint">&#64;Override
88public Object onRetainNonConfigurationInstance() {
89    final LoadedPhoto[] list = new LoadedPhoto[numberOfPhotos];
90    keepPhotos(list);
91    return list;
92}
93</pre>
94
95<p>In the new activity, in <code>onCreate()</code>, all you have to do to
96get your object back is to call {@link android.app.Activity#getLastNonConfigurationInstance()}.
97In Photostream, <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#251">this method is invoked</a>
98and if the returned value is not null, the grid is loaded with the list of
99photos from the previous activity:</p>
100
101<pre class="prettyprint">private void loadPhotos() {
102    final Object data = getLastNonConfigurationInstance();
103
104    // The activity is starting for the first time, load the photos from Flickr
105    if (data == null) {
106        mTask = new GetPhotoListTask().execute(mCurrentPage);
107    } else {
108        // The activity was destroyed/created automatically, populate the grid
109        // of photos with the images loaded by the previous activity
110        final LoadedPhoto[] photos = (LoadedPhoto[]) data;
111        for (LoadedPhoto photo : photos) {
112            addPhoto(photo);
113        }
114    }
115}
116</pre>
117
118<p>Be very careful with the object you pass through
119<code>onRetainNonConfigurationChange()</code>, though. If the object you
120pass is for some reason tied to the Activity/Context, <a
121href="http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/">you will leak</a>
122all the views and resources of the activity. This means you should
123never pass a View, a Drawable, an Adapter, etc. Photostream for
124instance extracts the bitmaps from the drawables and pass the bitmaps
125only, not the drawables. Finally, remember that
126<code>onRetainNonConfigurationChange()</code> should be used only to retain
127data that is expensive to load. Otherwise, keep it simple and let Android
128do everything.</p>
129