Android App Lifecycle Explained: Why Your AI-Generated App Survives Rotation
When you generate an Android app with AI (or write one manually), one of the most critical concepts to understand is the Activity lifecycle. Why? Because your app will crash, rotate, and go to sleep—and if you don't handle it correctly, users will lose their data or see a blank screen. Let's break it down.
The Activity Lifecycle: The Five States
An Android Activity goes through five main states:
onCreate() → onStart() → onResume() → [Activity visible and interactive]
↓
onPause() → onStop() → onDestroy()
Here's what each one does:
1. onCreate()
- Called when the Activity is first created
- Initialize UI, set up data bindings
- This is where you restore saved state (more on that later)
2. onStart()
- Activity is becoming visible to the user
- Resources like cameras or location can be started
- Not interactive yet
3. onResume()
- Activity is now fully interactive
- The user can tap buttons, input text, etc.
- This is where you start animations or resume video playback
4. onPause()
- User is leaving the Activity (another app came to foreground)
- Save critical data here
- Stop animations, pause video
- Note: You have ~500ms before the system kills your app
5. onStop()
- Activity is no longer visible
- Clean up heavy resources like database connections
- The system might kill your app here to free memory
6. onDestroy()
- Activity is being destroyed
- Either the user pressed Back, or the system is killing it
- Final cleanup
The Problem: Configuration Changes (Rotation)
When the user rotates their phone, Android does something brutal: it destroys the current Activity and recreates it from scratch.
Here's the sequence:
User rotates phone
↓
onPause() → onStop() → onDestroy() [old Activity destroyed]
↓
onCreate() → onStart() → onResume() [new Activity created]
This means:
- All local variables are lost
- Any data you were holding in memory is gone
- UI state is reset
- Users see a flash/flicker as the UI rebuilds
This is why many AI-generated apps crash on rotation. The developer didn't save state properly.
Solution 1: Using ViewModel to Survive Configuration Changes
ViewModel is a special Jetpack component that survives configuration changes. Data stored in ViewModel is NOT destroyed when the Activity rotates.
Kotlin Code Example:
// 1. Define your ViewModel
class UserViewModel : ViewModel() {
private val _userName = MutableLiveData<String>("")
val userName: LiveData<String> = _userName
fun setUserName(name: String) {
_userName.value = name
}
}
// 2. In your Activity, use the ViewModel
class MainActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val nameInput = findViewById<EditText>(R.id.nameInput)
// When user types, save to ViewModel
nameInput.addTextChangedListener { text ->
viewModel.setUserName(text.toString())
}
// Observe ViewModel data
viewModel.userName.observe(this) { name ->
nameInput.setText(name)
}
}
}
Why this works:
- ViewModel is scoped to the Activity
- Android keeps it alive during configuration changes
- Your data persists through rotation
- UI automatically updates via LiveData
Solution 2: Using Jetpack Compose with rememberSaveable
If you're using Compose (modern Android UI framework), the pattern is even simpler:
@Composable
fun UserScreen() {
// This state survives rotation because of rememberSaveable
var userName by rememberSaveable { mutableStateOf("") }
Column {
TextField(
value = userName,
onValueChange = { userName = it },
label = { Text("Enter your name") }
)
Text("Hello, $userName!")
}
}
Key differences:
-
remember { }does NOT survive rotation (lost on destroy) -
rememberSaveable { }DOES survive rotation (saved to Bundle) - Compose automatically restores state when the recomposition happens
How Compose Recomposition Works:
When rotation happens:
- Activity is destroyed →
rememberSaveablestate is saved to a Bundle - Activity is recreated →
rememberSaveablerestores the Bundle - Compose recomposes the UI tree
-
TextFieldis rendered with the restored value
User rotates phone
↓
rememberSaveable saves state → Activity destroyed
↓
Activity recreated → rememberSaveable restores state
↓
Compose recomposes → TextField shows saved text
Solution 3: Saving to savedInstanceState (onSaveInstanceState)
For more complex data, use the onSaveInstanceState() callback:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val nameInput = findViewById<EditText>(R.id.nameInput)
// Restore from saved state
if (savedInstanceState != null) {
val savedName = savedInstanceState.getString("userName", "")
nameInput.setText(savedName)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val nameInput = findViewById<EditText>(R.id.nameInput)
outState.putString("userName", nameInput.text.toString())
}
}
Limitations:
- Only works for Parcelable/Serializable objects
- Bundle has a ~1MB size limit
- Not ideal for large datasets
Preventing Rotation: Disabling Configuration Changes (Not Recommended)
You can force your Activity to NOT rotate:
<!-- AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="portrait" />
Why NOT to do this:
- Users hate apps that don't rotate
- You break accessibility for people who rely on rotation
- AI-generated apps that ignore rotation get bad reviews
When Your App Dies: Process Death
Android can kill your entire process in the background to free memory. This is different from configuration changes.
Sequence:
User backgrounded your app
↓
System needs memory
↓
System kills your process (calls onDestroy())
↓
User returns to your app
↓
System recreates the entire app stack
onSaveInstanceState() still works here, but only for UI state. For important data:
- Use a local database (Room)
- Use SharedPreferences
- Use DataStore (Jetpack)
// Room example
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
@Dao
interface UserDao {
@Insert
suspend fun insertUser(user: User)
@Query("SELECT * FROM users LIMIT 1")
fun getUser(): Flow<User>
}
When your app restarts, query the database:
class MainActivity : AppCompatActivity() {
private val db = AppDatabase.getInstance(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
val user = db.userDao().getUser().collect { user ->
// Restore UI with user data
}
}
}
}
Summary Table
| Scenario | Solution | Survives | Data Limit |
|---|---|---|---|
| Configuration change (rotation) | ViewModel + LiveData | Yes | No limit |
| Configuration change (Compose) | rememberSaveable | Yes | ~1MB (Bundle) |
| Brief pause (onPause) | ViewModel | Yes | No limit |
| Process death | Room/SharedPreferences | Yes | Device storage |
| User presses Back | Not saved | No | N/A |
AI-Generated Apps and Lifecycle
When you use Claude Code or other AI to generate an Android app, always verify:
- ✅ Does it handle rotation without crashing?
- ✅ Does it use ViewModel or rememberSaveable?
- ✅ Does it persist important data to a database?
- ✅ Does it properly implement onPause() for cleanup?
Bad AI-generated apps:
- Ignore the lifecycle entirely
- Lose data on rotation
- Crash on process death
- Don't save user input
Our templates handle all of this correctly.
The Diagram (For Reference)
┌────────────────────────────────────────────────┐
│ Activity Lifecycle Flow │
└────────────────────────────────────────────────┘
onCreate()
↓
onStart()
↓
onResume() ← [User interacting]
↙ ↖
onPause() [Rotation: destroys & recreates]
↓
onStop()
↓
onDestroy()
ViewModel survives rotation ✓
rememberSaveable survives rotation ✓
Local variables do NOT survive rotation ✗
Conclusion
Android's lifecycle is complex, but it's not magic. The key is:
- Use ViewModel or rememberSaveable for UI state
- Use Room/SharedPreferences for persistent data
- Save state in onSaveInstanceState() for edge cases
- Test rotation before shipping
All 8 templates handle lifecycle correctly. https://myougatheax.gumroad.com
Top comments (0)