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