| page.title=Handling Runtime Changes | |
| page.tags=activity,lifecycle | |
| @jd:body | |
| <div id="qv-wrapper"> | |
| <div id="qv"> | |
| <h2>In this document</h2> | |
| <ol> | |
| <li><a href="#RetainingAnObject">Retaining an Object During a Configuration Change</a></li> | |
| <li><a href="#HandlingTheChange">Handling the Configuration Change Yourself</a> | |
| </ol> | |
| <h2>See also</h2> | |
| <ol> | |
| <li><a href="providing-resources.html">Providing Resources</a></li> | |
| <li><a href="accessing-resources.html">Accessing Resources</a></li> | |
| <li><a href="http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html">Faster | |
| Screen Orientation Change</a></li> | |
| </ol> | |
| </div> | |
| </div> | |
| <p>Some device configurations can change during runtime | |
| (such as screen orientation, keyboard availability, and language). When such a change occurs, | |
| Android restarts the running | |
| {@link android.app.Activity} ({@link android.app.Activity#onDestroy()} is called, followed by {@link | |
| android.app.Activity#onCreate(Bundle) onCreate()}). The restart behavior is designed to help your | |
| application adapt to new configurations by automatically reloading your application with | |
| alternative resources that match the new device configuration.</p> | |
| <p>To properly handle a restart, it is important that your activity restores its previous | |
| state through the normal <a | |
| href="{@docRoot}guide/components/activities.html#Lifecycle">Activity | |
| lifecycle</a>, in which Android calls | |
| {@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} before it destroys | |
| your activity so that you can save data about the application state. You can then restore the state | |
| during {@link android.app.Activity#onCreate(Bundle) onCreate()} or {@link | |
| android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()}.</p> | |
| <p>To test that your application restarts itself with the application state intact, you should | |
| invoke configuration changes (such as changing the screen orientation) while performing various | |
| tasks in your application. Your application should be able to restart at any time without loss of | |
| user data or state in order to handle events such as configuration changes or when the user receives | |
| an incoming phone call and then returns to your application much later after your application | |
| process may have been destroyed. To learn how you can restore your activity state, read about the <a | |
| href="{@docRoot}guide/components/activities.html#Lifecycle">Activity lifecycle</a>.</p> | |
| <p>However, you might encounter a situation in which restarting your application and | |
| restoring significant amounts of data can be costly and create a poor user experience. In such a | |
| situation, you have two other options:</p> | |
| <ol type="a"> | |
| <li><a href="#RetainingAnObject">Retain an object during a configuration change</a> | |
| <p>Allow your activity to restart when a configuration changes, but carry a stateful | |
| object to the new instance of your activity.</p> | |
| </li> | |
| <li><a href="#HandlingTheChange">Handle the configuration change yourself</a> | |
| <p>Prevent the system from restarting your activity during certain configuration | |
| changes, but receive a callback when the configurations do change, so that you can manually update | |
| your activity as necessary.</p> | |
| </li> | |
| </ol> | |
| <h2 id="RetainingAnObject">Retaining an Object During a Configuration Change</h2> | |
| <p>If restarting your activity requires that you recover large sets of data, re-establish a network | |
| connection, or perform other intensive operations, then a full restart due to a configuration change | |
| might be a slow user experience. Also, it might not be possible for you to completely restore your | |
| activity state with the {@link android.os.Bundle} that the system saves for you with the {@link | |
| android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} callback—it is not | |
| designed to carry large objects (such as bitmaps) and the data within it must be serialized then | |
| deserialized, which can consume a lot of memory and make the configuration change slow. In such a | |
| situation, you can alleviate the burden of reinitializing your activity by retaining a {@link | |
| android.app.Fragment} when your activity is restarted due to a configuration change. This fragment | |
| can contain references to stateful objects that you want to retain.</p> | |
| <p>When the Android system shuts down your activity due to a configuration change, the fragments | |
| of your activity that you have marked to retain are not destroyed. You can add such fragments to | |
| your activity to preserve stateful objects.</p> | |
| <p>To retain stateful objects in a fragment during a runtime configuration change:</p> | |
| <ol> | |
| <li>Extend the {@link android.app.Fragment} class and declare references to your stateful | |
| objects.</li> | |
| <li>Call {@link android.app.Fragment#setRetainInstance(boolean)} when the fragment is created. | |
| </li> | |
| <li>Add the fragment to your activity.</li> | |
| <li>Use {@link android.app.FragmentManager} to retrieve the fragment when the activity is | |
| restarted.</li> | |
| </ol> | |
| <p>For example, define your fragment as follows:</p> | |
| <pre> | |
| public class RetainedFragment extends Fragment { | |
| // data object we want to retain | |
| private MyDataObject data; | |
| // this method is only called once for this fragment | |
| @Override | |
| public void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| // retain this fragment | |
| setRetainInstance(true); | |
| } | |
| public void setData(MyDataObject data) { | |
| this.data = data; | |
| } | |
| public MyDataObject getData() { | |
| return data; | |
| } | |
| } | |
| </pre> | |
| <p class="caution"><strong>Caution:</strong> While you can store any object, you | |
| should never pass an object that is tied to the {@link android.app.Activity}, such as a {@link | |
| android.graphics.drawable.Drawable}, an {@link android.widget.Adapter}, a {@link android.view.View} | |
| or any other object that's associated with a {@link android.content.Context}. If you do, it will | |
| leak all the views and resources of the original activity instance. (Leaking resources | |
| means that your application maintains a hold on them and they cannot be garbage-collected, so | |
| lots of memory can be lost.)</p> | |
| <p>Then use {@link android.app.FragmentManager} to add the fragment to the activity. | |
| You can obtain the data object from the fragment when the activity starts again during runtime | |
| configuration changes. For example, define your activity as follows:</p> | |
| <pre> | |
| public class MyActivity extends Activity { | |
| private RetainedFragment dataFragment; | |
| @Override | |
| public void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| setContentView(R.layout.main); | |
| // find the retained fragment on activity restarts | |
| FragmentManager fm = getFragmentManager(); | |
| dataFragment = (DataFragment) fm.findFragmentByTag(“data”); | |
| // create the fragment and data the first time | |
| if (dataFragment == null) { | |
| // add the fragment | |
| dataFragment = new DataFragment(); | |
| fm.beginTransaction().add(dataFragment, “data”).commit(); | |
| // load the data from the web | |
| dataFragment.setData(loadMyData()); | |
| } | |
| // the data is available in dataFragment.getData() | |
| ... | |
| } | |
| @Override | |
| public void onDestroy() { | |
| super.onDestroy(); | |
| // store the data in the fragment | |
| dataFragment.setData(collectMyLoadedData()); | |
| } | |
| } | |
| </pre> | |
| <p>In this example, {@link android.app.Activity#onCreate(Bundle) onCreate()} adds a fragment | |
| or restores a reference to it. {@link android.app.Activity#onCreate(Bundle) onCreate()} also | |
| stores the stateful object inside the fragment instance. | |
| {@link android.app.Activity#onDestroy() onDestroy()} updates the stateful object inside the | |
| retained fragment instance.</p> | |
| <h2 id="HandlingTheChange">Handling the Configuration Change Yourself</h2> | |
| <p>If your application doesn't need to update resources during a specific configuration | |
| change <em>and</em> you have a performance limitation that requires you to | |
| avoid the activity restart, then you can declare that your activity handles the configuration change | |
| itself, which prevents the system from restarting your activity.</p> | |
| <p class="note"><strong>Note:</strong> Handling the configuration change yourself can make it much | |
| more difficult to use alternative resources, because the system does not automatically apply them | |
| for you. This technique should be considered a last resort when you must avoid restarts due to a | |
| configuration change and is not recommended for most applications.</p> | |
| <p>To declare that your activity handles a configuration change, edit the appropriate <a | |
| href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element in | |
| your manifest file to include the <a | |
| href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code | |
| android:configChanges}</a> attribute with a value that represents the configuration you want to | |
| handle. Possible values are listed in the documentation for the <a | |
| href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code | |
| android:configChanges}</a> attribute (the most commonly used values are {@code "orientation"} to | |
| prevent restarts when the screen orientation changes and {@code "keyboardHidden"} to prevent | |
| restarts when the keyboard availability changes). You can declare multiple configuration values in | |
| the attribute by separating them with a pipe {@code |} character.</p> | |
| <p>For example, the following manifest code declares an activity that handles both the | |
| screen orientation change and keyboard availability change:</p> | |
| <pre> | |
| <activity android:name=".MyActivity" | |
| android:configChanges="orientation|keyboardHidden" | |
| android:label="@string/app_name"> | |
| </pre> | |
| <p>Now, when one of these configurations change, {@code MyActivity} does not restart. | |
| Instead, the {@code MyActivity} receives a call to {@link | |
| android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. This method | |
| is passed a {@link android.content.res.Configuration} object that specifies | |
| the new device configuration. By reading fields in the {@link android.content.res.Configuration}, | |
| you can determine the new configuration and make appropriate changes by updating | |
| the resources used in your interface. At the | |
| time this method is called, your activity's {@link android.content.res.Resources} object is updated | |
| to return resources based on the new configuration, so you can easily | |
| reset elements of your UI without the system restarting your activity.</p> | |
| <p class="caution"><strong>Caution:</strong> Beginning with Android 3.2 (API level 13), <strong>the | |
| "screen size" also changes</strong> when the device switches between portrait and landscape | |
| orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing | |
| for API level 13 or higher (as declared by the <a | |
| href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> and <a | |
| href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> | |
| attributes), you must include the {@code "screenSize"} value in addition to the {@code | |
| "orientation"} value. That is, you must decalare {@code | |
| android:configChanges="orientation|screenSize"}. However, if your application targets API level | |
| 12 or lower, then your activity always handles this configuration change itself (this configuration | |
| change does not restart your activity, even when running on an Android 3.2 or higher device).</p> | |
| <p>For example, the following {@link | |
| android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} implementation | |
| checks the current device orientation:</p> | |
| <pre> | |
| @Override | |
| public void onConfigurationChanged(Configuration newConfig) { | |
| super.onConfigurationChanged(newConfig); | |
| // Checks the orientation of the screen | |
| if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { | |
| Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); | |
| } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ | |
| Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); | |
| } | |
| } | |
| </pre> | |
| <p>The {@link android.content.res.Configuration} object represents all of the current | |
| configurations, not just the ones that have changed. Most of the time, you won't care exactly how | |
| the configuration has changed and can simply re-assign all your resources that provide alternatives | |
| to the configuration that you're handling. For example, because the {@link | |
| android.content.res.Resources} object is now updated, you can reset | |
| any {@link android.widget.ImageView}s with {@link android.widget.ImageView#setImageResource(int) | |
| setImageResource()} | |
| and the appropriate resource for the new configuration is used (as described in <a | |
| href="providing-resources.html#AlternateResources">Providing Resources</a>).</p> | |
| <p>Notice that the values from the {@link | |
| android.content.res.Configuration} fields are integers that are matched to specific constants | |
| from the {@link android.content.res.Configuration} class. For documentation about which constants | |
| to use with each field, refer to the appropriate field in the {@link | |
| android.content.res.Configuration} reference.</p> | |
| <p class="note"><strong>Remember:</strong> When you declare your activity to handle a configuration | |
| change, you are responsible for resetting any elements for which you provide alternatives. If you | |
| declare your activity to handle the orientation change and have images that should change | |
| between landscape and portrait, you must re-assign each resource to each element during {@link | |
| android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}.</p> | |
| <p>If you don't need to update your application based on these configuration | |
| changes, you can instead <em>not</em> implement {@link | |
| android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. In | |
| which case, all of the resources used before the configuration change are still used | |
| and you've only avoided the restart of your activity. However, your application should always be | |
| able to shutdown and restart with its previous state intact, so you should not consider this | |
| technique an escape from retaining your state during normal activity lifecycle. Not only because | |
| there are other configuration changes that you cannot prevent from restarting your application, but | |
| also because you should handle events such as when the user leaves your application and it gets | |
| destroyed before the user returns to it.</p> | |
| <p>For more about which configuration changes you can handle in your activity, see the <a | |
| href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code | |
| android:configChanges}</a> documentation and the {@link android.content.res.Configuration} | |
| class.</p> |