Table of Contents
Why Configuration Changes Matter
Android devices can change state at any time. The most common example is a rotation from portrait to landscape, but there are many other situations. A configuration change is any change to device or system settings that affects how your app should present itself or behave, such as screen orientation, language, screen size, or system theme.
When a configuration changes, Android may destroy and recreate your Activity. This behavior is central to how Android ensures that your app always uses the correct resources for the current device state. Understanding configuration changes is essential because it directly affects how you keep user data and UI state safe during these transitions.
What Counts as a Configuration Change
A configuration change happens when certain characteristics of the device or system change. Orientation is the one you see most often while developing, but it is not the only one.
Typical configuration changes include orientation changes, switching between portrait and landscape. Screen size or layout changes, for example when the user switches to multi window mode, or when the app is used on a foldable device that is folded or unfolded. Language or locale changes, when the user selects another language in system settings. UI mode changes, like switching between light and dark mode. Keyboard availability and input device changes, such as connecting a hardware keyboard. Screen density or font scale changes, when the user increases text size or when the density category changes.
You do not need to memorize all possible configuration changes, but you must understand that several different events can trigger the same lifecycle pattern: activity destruction followed by recreation.
Default System Behavior on Configuration Changes
By default, when a configuration change occurs, Android follows a specific sequence. The existing Activity instance receives lifecycle callbacks that you will study in detail in the lifecycle chapters. It reaches onPause, then onStop, and finally onDestroy. After destruction, Android creates a new instance of the Activity. The system then calls its creation lifecycle methods again, such as onCreate, followed by onStart and onResume.
From the perspective of your code, a configuration change often looks like a very fast exit from the current screen and a return to the same screen. All your member variables in the Activity instance are lost because this is a new object. View references that belonged to the old layout are gone, and a new layout is inflated.
Android uses this recreation process to reload appropriate resources. For example, if you have activity_main.xml in both layout and layout_land, the system chooses the portrait version in portrait, and the landscape version in landscape. The same is true for different language resources and other qualifiers.
Configuration changes cause your Activity to be destroyed and recreated by default, and any data stored only in the Activity instance is lost unless you handle it correctly.
What Happens to UI and Data
When your Activity is recreated after a configuration change, several different types of state behave differently.
Layout and views are recreated by inflating the XML again in onCreate. Any visual configuration that depends on layout attributes or resource qualifiers will update automatically.
Resource based content updates to match the new configuration. For example, string resources change when the language changes, and drawable resources can switch to a density specific version or a dark mode variation.
User entered data and temporary values inside views can behave differently. Simple text in standard input widgets such as EditText is often restored automatically by the system. However, this is not guaranteed for every view type or for custom views, and you should not depend on it without testing.
In memory variables such as counters, timers, or objects you store in fields of the Activity are lost when the Activity instance is destroyed. If you want to keep them across configuration changes, you must use a dedicated mechanism such as onSaveInstanceState, a ViewModel, or other architecture components that live longer than the Activity instance.
Network calls or background tasks that are tied only to the Activity instance will not automatically survive a configuration change. You will address lifecycle aware tasks in a later chapter.
Using onSaveInstanceState and onRestoreInstanceState
Android provides a simple mechanism to preserve small pieces of UI related data across configuration changes, the instance state bundle. Before your Activity is destroyed, the system calls onSaveInstanceState. You receive a Bundle object where you can store primitive types and simple objects that implement Parcelable or Serializable. When the Activity is recreated, this bundle is passed back to you in onCreate and in onRestoreInstanceState.
A minimal example looks like this:
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("SCORE_KEY", currentScore)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState != null) {
currentScore = savedInstanceState.getInt("SCORE_KEY", 0)
}
}
In this example, currentScore survives an orientation change because you explicitly save it and restore it.
The instance state is meant for small pieces of transient UI state. This includes things like which tab is selected, the current scroll position, input text, or a simple counter. It is not appropriate for large data sets, heavy objects, or long running operations.
Use onSaveInstanceState to store only small and lightweight data that you need to restore the current UI state, not large objects or long term app data.
Android may also call onSaveInstanceState if the system needs to reclaim memory and destroy your activity in the background. In that case, the saved state can be used later if the user returns to your activity, even without a configuration change. Because of this, using the instance state is safer than relying only on member variables.
onRestoreInstanceState is called after onStart and only when there actually is a saved state. You can use it if you prefer to separate restoration logic from onCreate, but both receive the same Bundle content. Many developers choose to read savedInstanceState directly in onCreate to keep initialization in one place.
Configuration Changes and Activity Lifecycle
Configuration changes are tightly connected to the activity lifecycle. The destruction and recreation sequence you observed in the lifecycle chapter is exactly what happens on a configuration change, with one important addition: the instance state bundle.
The typical order looks like this when you rotate the device. The current Activity receives onPause, then onSaveInstanceState, then onStop, then onDestroy. A new Activity instance is created, then onCreate with a non null savedInstanceState, followed by onStart, possibly onRestoreInstanceState, and then onResume.
Using the lifecycle callbacks correctly lets you choose where to initialize brand new state and where to restore previous state only when it exists. Initialization that should always happen, even for a fresh start, usually goes in onCreate before you check the savedInstanceState. Restoration that should run only when there was a previous instance usually happens inside a conditional check for a non null savedInstanceState.
Understanding this link between lifecycle events and configuration changes helps you avoid subtle bugs. For example, if you start a repeating timer in onCreate and start another one in onCreate after each rotation without canceling the previous one, you accumulate multiple timers. Lifecycle awareness and careful state handling prevents this.
Alternative Strategies: ViewModel and Architecture Components
While onSaveInstanceState is useful, it is not the only tool you can use. Modern Android apps usually rely on architecture components that are designed to survive configuration changes without requiring you to rebuild complex objects every time.
A ViewModel object is associated with a lifecycle owner such as an Activity or Fragment. When the configuration changes and the Activity is recreated, the same ViewModel instance is provided to the new Activity instance. This lets you store UI related data in the ViewModel instead of the Activity itself.
An example idea is to keep your current list of items from a network call in a ViewModel. When the device rotates, the new Activity gets the same ViewModel and can read the existing data, which avoids repeating the network request.
You will learn details about ViewModel, LiveData, and the MVVM architecture in later chapters. For configuration changes, the key idea is that you should avoid storing important, non trivial state only in your Activity. Place it in components that are designed to outlive the Activity instance.
A good pattern is to combine both approaches. Use a ViewModel for your core screen data, such as lists and domain objects. Use onSaveInstanceState for purely UI state, such as the currently selected filter option or which item is expanded, that you want to restore after short term destruction.
Avoiding Manual Handling with configChanges
Android allows you to change the default behavior for some configuration changes by declaring android:configChanges attributes in your AndroidManifest.xml. When you do this for certain configuration types, Android will not destroy and recreate the Activity automatically. Instead, it calls onConfigurationChanged in your existing Activity instance.
For example, you might see code like this in older tutorials:
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize" />
With this declaration, orientation changes will not trigger the usual destroy and recreate cycle. The system will call onConfigurationChanged and it becomes your responsibility to update the UI for the new orientation.
Although this can look attractive because it avoids dealing with recreation and state restoration, it is usually not recommended for most apps. Skipping recreation can cause your app to ignore updated resources for the new configuration, and handling all updates manually is harder and more error prone.
Avoid using android:configChanges to bypass activity recreation except in very specific and advanced cases. The recommended approach is to support the default destroy and recreate behavior correctly.
If you do use onConfigurationChanged in rare cases, you must manually update any resources, layout elements, or calculations that depend on the changed configuration, which is more work than simply letting Android reload the proper resources.
Designing Layouts that Adapt to Configuration Changes
Configuration changes are not only about lifecycle and data. They are also about how your UI adapts to new conditions. Orientation changes and different screen sizes may require different layouts. Android supports this through resource qualifiers and responsive design.
You can place different versions of the same layout file in different resource folders. For example, res/layout/activity_main.xml for the default portrait orientation and res/layout-land/activity_main.xml for landscape. When the device rotates, the system picks the correct file automatically during recreation.
Instead of writing logic to rearrange views in code, you can prepare alternate resources for different configurations. Layout qualifiers also exist for screen width, smallest width, language, and many other properties. Combined with adaptive design principles from other chapters, this lets your UI look appropriate on phones, tablets, and foldables without manual recalculation.
Because configuration changes recreate the Activity, the new layout is automatically inflated from the appropriate resource folder. This is another reason why destroying and recreating activities is a useful behavior instead of a problem to avoid.
Testing Configuration Changes While Developing
To build apps that behave correctly under configuration changes, you should intentionally test these scenarios during development. One straightforward method is to run your app on the emulator or a device and simply rotate the screen repeatedly while observing what happens.
Look for disappearing user input, such as text fields that clear unexpectedly. Watch for crashes that occur after rotation, which often indicate that some object you assumed still exists has been destroyed. Check that long operations like network calls do not restart unnecessarily or create duplicate results.
The Android Studio emulator enables you to test additional configuration changes. You can switch between light and dark mode, change language and locale, adjust font size and display size, and test multi window mode. Each of these changes may trigger activity recreation and resource reloading.
By practicing this frequently, you learn to predict where you need to save state or use a ViewModel. Problems caused by configuration changes often appear only when a screen is recreated, so treating rotation as a normal test step helps you discover these issues early.
Putting It All Together
Configuration changes are a natural and frequent part of Android app behavior. The system uses them to keep your app aligned with the current device context. When a configuration change occurs, Android destroys and recreates your Activity, reloads the appropriate resources, and gives you an opportunity to restore important state.
Your job as a developer is not to fight this process but to cooperate with it. Use onSaveInstanceState for small UI related values, rely on architecture components such as ViewModel for data that should survive recreation, and organize your resources so that layouts adapt naturally to different configurations. Avoid quick fixes that bypass recreation unless you have a specific and well understood reason.
With these patterns, configuration changes become predictable events instead of surprising bugs, and your app will feel more stable and polished on the wide variety of Android devices and setups.