Android App Lifecycle Explained: Why Your AI-Generated App Survives Rotation

Published: (March 1, 2026 at 07:15 PM EST)
7 min read
Source: Dev.to

Source: Dev.to

The Activity Lifecycle: The Five States

onCreate() → onStart() → onResume() → [Activity visible and interactive]

                                    onPause() → onStop() → onDestroy()

1. onCreate()

  • Called when the Activity is first created.
  • Initialize UI, set up data bindings.
  • Restore saved state (more on that later).

2. onStart()

  • Activity becomes visible to the user.
  • Start resources like cameras or location services.
  • Not interactive yet.

3. onResume()

  • Activity is now fully interactive.
  • Users can tap buttons, input text, etc.
  • Start animations or resume video playback.

4. onPause()

  • User is leaving the Activity (another app came to the foreground).
  • Save critical data here.
  • Stop animations, pause video.
  • Note: You have ~500 ms before the system may kill your app.

5. onStop()

  • Activity is no longer visible.
  • Clean up heavy resources (e.g., database connections).
  • The system might kill your app here to free memory.

6. onDestroy()

  • Activity is being destroyed (user pressed Back or the system is killing it).
  • Final cleanup.

The Problem: Configuration Changes (Rotation)

When the user rotates the phone, Android destroys the current Activity and recreates it from scratch.

User rotates phone

onPause() → onStop() → onDestroy()   [old Activity destroyed]

onCreate() → onStart() → onResume()  [new Activity created]

Consequences

  • All local variables are lost.
  • Any in‑memory data disappears.
  • 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 Jetpack component that survives configuration changes. Data stored in a ViewModel is not destroyed when the Activity rotates.

Kotlin Code Example

// 1. Define your ViewModel
class UserViewModel : ViewModel() {
    private val _userName = MutableLiveData("")
    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 (the 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

Compose functionRotation survival
remember { }No – state is lost on destroy
rememberSaveable { }Yes – saved to a Bundle and restored

Compose automatically restores the saved state when the Activity is recreated.

How Compose Recomposition Works

When rotation happens:

  1. Activity is destroyedrememberSaveable saves its state to a Bundle.
  2. Activity is recreatedrememberSaveable restores the state from the Bundle.
  3. Compose recomposes the UI tree, rendering the TextField 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())
    }
}

onSaveInstanceState is called before the Activity is destroyed, allowing you to place primitive types, Parcelables, or Serializables into the Bundle. When the Activity is recreated, the saved values are available in onCreate (or onRestoreInstanceState).

TL;DR

  • Activity lifecycle determines when you can safely allocate and release resources.
  • Rotation triggers a full destroy/recreate cycle, wiping out in‑memory state.
  • ViewModel, rememberSaveable, and onSaveInstanceState are the three primary ways to preserve data across configuration changes.

Implement one (or a combination) of these strategies, and your AI‑generated Android app will survive rotation gracefully.

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putString("userName", nameInput.text.toString())
}

Limitations

  • Only works for Parcelable/Serializable objects.
  • Bundle has a ~1 MB size limit.
  • Not ideal for large data sets.
<!-- Add to your Activity declaration in AndroidManifest.xml -->
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden"
    android:screenOrientation="portrait" />

Why NOT to do this

  • Users dislike apps that don’t rotate.
  • You break accessibility for people who rely on rotation.
  • AI‑generated apps that ignore rotation receive bad reviews.

When Your App Dies: Process Death

Android can kill your entire process in the background to free memory. This is different from a configuration change.

Sequence

User backgrounds 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 persistent storage:

  • Room (local database)
  • SharedPreferences
  • 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>
}

Restoring Data After a Restart

class MainActivity : AppCompatActivity() {
    private val db = AppDatabase.getInstance(this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launch {
            db.userDao().getUser().collect { user ->
                // Restore UI with user data
            }
        }
    }
}

Summary Table

ScenarioSolutionSurvives Rotation?Data Limit
Configuration change (rotation)ViewModel + LiveDataYesNo limit
Configuration change (Compose)rememberSaveableYes~1 MB (Bundle)
Brief pause (onPause)ViewModelYesNo limit
Process deathRoom / SharedPreferences / DataStoreYesDevice storage
User presses BackNot savedNoN/A

AI‑Generated Apps and Lifecycle

When you use Claude Code or any 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?

Common issues in poorly generated apps

  • Ignoring the lifecycle entirely.
  • Losing data on rotation.
  • Crashing on process death.
  • Not saving 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 isn’t magic. The key take‑aways:

  • Use ViewModel or rememberSaveable for UI state.
  • Use Room, SharedPreferences, or DataStore for persistent data.
  • Save state in onSaveInstanceState() for edge cases.
  • Test rotation before shipping.

All 8 templates handle the lifecycle correctly.

https://myougatheax.gumroad.com

0 views
Back to Blog

Related posts

Read more »