Home | History | Annotate | Download | only in articles
      1 page.title=Faster Screen Orientation Change
      2 parent.title=Articles
      3 parent.link=../browser.html?tag=article
      4 @jd:body
      5 
      6 
      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
     13 Changes</a></li>
     14   </ol>
     15 
     16 </div>
     17 </div>
     18 
     19 <p>Android is designed to run efficiently on a wide
     20 array of devices, with very different hardware configurations. Some
     21 devices, like the T-Mobile G1, can change their hardware configuration
     22 at runtime. For instance, when you open the keyboard, the screen change
     23 from 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
     30 resources at run time is based on the alternate resources framework.</p>
     31 
     32 <p>Providing orientation-specific resources is an important part of 
     33 developing your app. If you are not familiar with resource directory qualifiers 
     34 or how the platform uses them, please read 
     35 <a href="{@docRoot}guide/topics/resources/resources-i18n.html#AlternateResources">
     36 Alternate Resources</a>.
     37 </div>
     38 </div>
     39 
     40 <p>To make
     41 Android app development easier, the Android system automatically handles
     42 configuration change events and restarts the current activity with the new
     43 configuration. This is the default behavior that lets you declare
     44 resources like layouts and drawables based on the orientation, screen
     45 size, locale, etc. </p>
     46 
     47 <p>While this behavior is really powerful, since your application adapts
     48 automatically to the device's configuration at runtime, it is sometimes
     49 confusing for new Android developers, who wonder why their activity is
     50 destroyed and recreated. </p>
     51 
     52 <p>Facing this "issue," some developers choose to handle configuration changes
     53 themselves which is, in general, a short-term solution that will only complicate
     54 their lives later. On the other hand, the system's automatic resource handling
     55 is a very efficient and easy way to adapt an application's user interface to
     56 various devices and devices configurations. It sometimes comes at a price,
     57 though.</p>
     58 
     59 <p>When your application displays a lot of data, or data that is expensive to fetch,
     60 the automatic destruction/creation of the activities can be lead to a
     61 painful 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>,
     62 a simple Flickr browsing application. After you launch the application and choose a Flickr account, the
     63 application downloads a set of 6 photos (on a T-Mobile G1) from the
     64 Flickr servers and displays them on screen. To improve the user
     65 experience, the application uses slightly different layouts and drawables in
     66 portrait 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
     73 screen is rotated. However, can you imagine how painful it would be for the user
     74 to see all the images being downloaded again? The obvious solution to this
     75 problem 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
     77 these techniques is adapted to the current situation: why should we bother
     78 caching the images when the screen is not rotated? Fortunately for us, Android
     79 offers 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 
     83 can be used to pass an arbitrary object to <em>your future self</em> and Android 
     84 is smart enough to call this method only when needed. In the case of Photostream, 
     85 the application used this method
     86 to pass the downloaded images to the future activity on orientation change. 
     87 The implementation can be summarized like so:</p>
     88 
     89 <pre class="prettyprint">&#64;Override
     90 public 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 
     98 get your object back is to call {@link android.app.Activity#getLastNonConfigurationInstance()}. 
     99 In Photostream, this method is invoked 
    100 and if the returned value is not null, the grid is loaded with the list of 
    101 photos 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 
    122 pass is for some reason tied to the Activity/Context, <a 
    123 href="http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/">you will leak</a>
    124 all the views and resources of the activity. This means you should
    125 never pass a View, a Drawable, an Adapter, etc. Photostream for
    126 instance extracts the bitmaps from the drawables and pass the bitmaps
    127 only, not the drawables. Finally, remember that 
    128 <code>onRetainNonConfigurationChange()</code> should be used only to retain 
    129 data that is expensive to load. Otherwise, keep it simple and let Android 
    130 do everything.</p>
    131 
    132 <p>Also read the guide to <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime
    133 Changes</a>.</p>
    134