Introduction
One of the biggest challenges in Android development is handling configuration changes, such as screen rotation, dark mode switches, or language changes. By default, when a configuration change occurs, the Activity is destroyed and recreated, leading to the loss of UI state and history.
What Happens During a Configuration Change?
A configuration change occurs when there is a fundamental change in the device environment that forces the system to recreate the Activity.
Common Causes of Configuration Changes
Screen Rotation – Switching between portrait and landscape mode.
System Language Change – Changing the device language from settings.
Dark Mode Toggle – Switching between light and dark themes.
Multi-Window Mode – Running multiple apps in split-screen.
How Does Android Handle Configuration Changes?
When a configuration change occurs:
The system destroys the current Activity.
A new instance of the Activity is created.
All UI state and user input are lost unless manually preserved.
Let’s now explore the best ways to handle these changes.
Method 1: Using ViewModel (Recommended Approach)
The ViewModel class is part of Jetpack’s Android Architecture Components and is designed to persist data across configuration changes.
Why Use ViewModel?
Retains data across configuration changes.
Does not require manual state saving.
Cleaner and more maintainable code.
Implementation:
Step 1: Create a ViewModel Class
class HistoryViewModel : ViewModel() {
var userText: String? = null
}
Step 2: Use ViewModel in Activity
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: HistoryViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(HistoryViewModel::class.java)
val editText = findViewById<EditText>(R.id.editText)
editText.setText(viewModel.userText)
editText.addTextChangedListener {
viewModel.userText = it.toString()
}
}
}
Result:
The ViewModel persists data even when the screen rotates.
The user’s text input is not lost.
Best for: Apps that need to maintain temporary UI state across configuration changes.
Method 2: Using onSaveInstanceState()
The onSaveInstanceState()
method allows us to save small UI state data before the Activity is destroyed and restore it in onCreate()
.
When to Use onSaveInstanceState()?
For small amounts of data like text input.
When you don’t need data persistence beyond app restarts.
Implementation:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val editText = findViewById<EditText>(R.id.editText)
editText.setText(savedInstanceState?.getString("user_text", ""))
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val editText = findViewById<EditText>(R.id.editText)
outState.putString("user_text", editText.text.toString())
}
}
How It Works:
onSaveInstanceState()
is called before the Activity is destroyed.
The stored data is retrieved in onCreate()
using the savedInstanceState Bundle.
Best for: Simple UI state preservation, such as text fields or scroll positions.
Limitations:
Data is lost if the app is force closed.
Cannot store complex objects.
Method 3: Using PersistableBundle for Persistent Data
If you need long-term data persistence, you can use PersistableBundle
. This is useful when data should persist even after an app restart.
Implementation:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_main)
}
override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
super.onSaveInstanceState(outState, outPersistentState)
outPersistentState.putString("user_text", "Persistent Data")
}
}
When to Use PersistableBundle?
When data should persist across app restarts.
When handling important user sessions.
Best for: Storing long-term preferences or user sessions.
Comparison of Methods
Method | Best Use Case | Survives App Restart? |
ViewModel | UI state, small data | ❌ No |
onSaveInstanceState() | Simple UI state like text fields | ❌ No |
PersistableBundle | Persistent storage across app restarts | ✅ Yes |
Best Practices for Preserving Activity History:
Use ViewModel for UI-related data across configuration changes.
Use onSaveInstanceState() for small, temporary UI states.
Use PersistableBundle for long-term data persistence.
Conclusion
Handling configuration changes effectively ensures a smooth user experience in Android apps.
ViewModel is the best approach for UI-related data.
onSaveInstanceState() is great for small temporary data.
PersistableBundle should be used for persistent storage needs.