What is the lifecycle of an Android application?
Answer
Overview
Android application lifecycle defines how the Android OS creates, pauses, resumes, and destroys app components. Understanding it is critical for managing resources, saving state, and building stable apps.
Android lifecycle operates at two main levels:
- Application level — the entire app process
- Activity level — each individual screen
Application Lifecycle
The
Applicationkotlinclass MyApplication : Application() { override fun onCreate() { super.onCreate() // Called when the app process is first created // ✅ Use for: app-wide init (Firebase, Timber, DI, crash reporting) FirebaseApp.initializeApp(this) Timber.plant(Timber.DebugTree()) } override fun onLowMemory() { super.onLowMemory() // Called when the overall system is running low on memory // ✅ Use for: releasing caches, large bitmaps } override fun onTrimMemory(level: Int) { super.onTrimMemory(level) // Called when the OS wants the app to trim its memory usage when (level) { TRIM_MEMORY_UI_HIDDEN -> clearUiCaches() TRIM_MEMORY_RUNNING_CRITICAL -> releaseAllCaches() } } override fun onTerminate() { super.onTerminate() // ⚠️ Only called in emulators — NEVER called on real devices // Do NOT rely on this for cleanup } }
Register it in
AndroidManifest.xmlxml<application android:name=".MyApplication" ... >
Activity Lifecycle
The Activity lifecycle is the core of Android development. Each screen (Activity) moves through these states as the user navigates.
text┌─────────────────────────────────┐ │ App Launched │ └──────────────┬──────────────────┘ ▼ ┌─────────┐ │onCreate()│ ← Activity created, inflate UI └────┬─────┘ ▼ ┌─────────┐ │onStart() │ ← Activity visible but not interactive └────┬─────┘ ▼ ┌──────────┐ │onResume()│ ← Activity in foreground, user can interact └────┬─────┘ │ ┌──────────────┴──────────────────┐ │ RUNNING (Active) │ └──────────────┬──────────────────┘ │ ┌─────────┴─────────┐ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │onPause() │ │onPause() │ └────┬─────┘ └────┬─────┘ │ │ Another activity Back button / partially covers fully hidden │ │ ▼ ▼ (still visible) ┌──────────┐ │onStop() │ ← Activity fully hidden └────┬─────┘ │ ┌──────────┴──────────┐ │ │ ▼ ▼ ┌────────────┐ ┌─────────────┐ │onRestart() │ │onDestroy() │ ← Permanently destroyed └─────┬──────┘ └─────────────┘ ▼ ┌──────────┐ │onStart() │ (back in lifecycle) └──────────┘
Activity Lifecycle Methods — Detailed
1. onCreate()
Called once when the Activity is first created. Set up UI, initialize ViewModel, restore saved state.
kotlinclass MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Inflate layout binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // Initialize ViewModel viewModel = ViewModelProvider(this)[MainViewModel::class.java] // Restore state if activity was recreated (rotation, etc.) savedInstanceState?.let { val savedText = it.getString("input_text", "") binding.editText.setText(savedText) } // Set up UI listeners binding.button.setOnClickListener { viewModel.loadData() } // Observe LiveData viewModel.data.observe(this) { data -> binding.textView.text = data } } }
✅ Do: Initialize views, ViewModel, observers, restore instance state ❌ Don't: Start animations, acquire camera/GPS, heavy background work
2. onStart()
Called when the Activity becomes visible to the user (but not yet interactive).
kotlinoverride fun onStart() { super.onStart() // Activity is visible — but not yet in foreground // ✅ Use for: registering broadcast receivers, starting animations // ✅ Use for: resuming operations paused in onStop() registerReceiver(networkReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)) }
✅ Do: Register broadcast receivers, resume animations ❌ Don't: Acquire exclusive resources (camera, microphone)
3. onResume()
Called when the Activity is in the foreground and fully interactive. This is the "running" state.
kotlinoverride fun onResume() { super.onResume() // Activity is fully interactive // ✅ Use for: start camera preview, resume video/audio, refresh data cameraPreview.start() sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_UI) viewModel.refreshIfNeeded() }
✅ Do: Start camera, sensors, video/audio playback, refresh UI data ❌ Don't: Do heavy initialization (too late, causes jank)
4. onPause()
Called when the Activity is partially obscured — another Activity is in front (e.g., dialog, transparent activity). The Activity is still visible but not focused.
kotlinoverride fun onPause() { super.onPause() // Activity partially hidden — release resources that waste battery/CPU // ✅ Use for: pause camera, sensors, video, save draft data // ⚠️ Keep this method FAST — the new activity won't resume until this returns cameraPreview.stop() sensorManager.unregisterListener(sensorListener) viewModel.saveDraft(binding.editText.text.toString()) }
✅ Do: Pause camera, sensors, playback, save lightweight state ❌ Don't: Do heavy work, async operations, save large data (blocks UI)
5. onStop()
Called when the Activity is completely hidden — another Activity covers it entirely, or user presses Home.
kotlinoverride fun onStop() { super.onStop() // Activity fully hidden — save data, release resources // ✅ Use for: unregister broadcast receivers, save to database // ✅ Safe to do heavier saves here (unlike onPause) unregisterReceiver(networkReceiver) viewModel.saveToDatabase() // Safe — runs on worker thread }
✅ Do: Save persistent data, unregister receivers, release heavy resources ❌ Don't: Rely on this always being called before
onDestroy()6. onRestart()
Called when the Activity is coming back from stopped state (user pressed Back from another activity, or returns from background).
kotlinoverride fun onRestart() { super.onRestart() // Activity is being restarted after being stopped // Called only when coming back — NOT on fresh launch // ✅ Use for: refresh stale data, re-check permissions viewModel.refreshData() }
Lifecycle after
onRestart()onStart()onResume()7. onDestroy()
Called when the Activity is permanently destroyed — user pressed Back,
finish()kotlinoverride fun onDestroy() { // Clean up ALL remaining resources // ✅ Use for: cancel coroutines, close DB connections, release NDK resources // ✅ Check isFinishing() to distinguish user-dismissed vs system-killed if (isFinishing) { // User explicitly closed the activity analyticsManager.logEvent("activity_closed") } else { // System killed for recreation (e.g., rotation) // State already saved in onSaveInstanceState } mediaPlayer?.release() super.onDestroy() }
✅ Do: Release all remaining resources, cancel background work ❌ Don't: Save important data here — it may not always be called
Saving & Restoring Instance State
When the system destroys and recreates an Activity (rotation, language change), you must save and restore UI state.
kotlin// Save state before Activity is destroyed override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("input_text", binding.editText.text.toString()) outState.putInt("scroll_position", binding.recyclerView.computeVerticalScrollOffset()) outState.putBoolean("is_expanded", isExpanded) } // Restore state in onCreate override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) savedInstanceState?.let { binding.editText.setText(it.getString("input_text")) binding.recyclerView.scrollBy(0, it.getInt("scroll_position")) isExpanded = it.getBoolean("is_expanded") } }
Tip: Use
to survive configuration changes withouttextViewModel— ViewModel persists across rotation.textonSaveInstanceState
Lifecycle by Scenario
| Scenario | Methods Called (in order) |
|---|---|
| App first launch | text text text |
| Home button pressed | text text |
| Return from background | text text text |
| Back button pressed | text text text |
| Screen rotation | text text text text text text |
| Another activity opens (full) | text text |
| Dialog / partial overlay opens | text |
| Phone call received | text text |
| System kills app (low memory) | text text |
| App comes to foreground after kill | text text text |
Process States (Android OS Perspective)
Android manages app processes in priority order. Lower priority processes are killed first when memory is needed.
| State | Description | Killed? |
|---|---|---|
| Foreground | Activity in text | Almost never |
| Visible | Activity visible but not focused ( text | Rarely |
| Service | Background service running | Under pressure |
| Background | Activity in text | Likely |
| Empty (Cached) | No active components — process kept for fast relaunch | First to be killed |
Complete Activity Example
kotlinclass ProfileActivity : AppCompatActivity() { private lateinit var binding: ActivityProfileBinding private lateinit var viewModel: ProfileViewModel private var sensorManager: SensorManager? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityProfileBinding.inflate(layoutInflater) setContentView(binding.root) viewModel = ViewModelProvider(this)[ProfileViewModel::class.java] val userId = intent.getStringExtra("userId") ?: return finish() viewModel.loadProfile(userId) viewModel.profile.observe(this) { binding.nameText.text = it.name } savedInstanceState?.let { binding.editBio.setText(it.getString("draft_bio")) } } override fun onStart() { super.onStart() registerReceiver(networkReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")) } override fun onResume() { super.onResume() sensorManager?.registerListener(stepListener, stepSensor, SensorManager.SENSOR_DELAY_UI) } override fun onPause() { super.onPause() sensorManager?.unregisterListener(stepListener) viewModel.saveDraft(binding.editBio.text.toString()) } override fun onStop() { super.onStop() unregisterReceiver(networkReceiver) viewModel.persistProfile() } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("draft_bio", binding.editBio.text.toString()) } override fun onDestroy() { sensorManager = null super.onDestroy() } }
Flutter Integration — AppLifecycleState
In Flutter, the Activity lifecycle is exposed through
AppLifecycleStateWidgetsBindingObserverdartclass MyScreen extends StatefulWidget { State<MyScreen> createState() => _MyScreenState(); } class _MyScreenState extends State<MyScreen> with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { case AppLifecycleState.resumed: // Equivalent to onResume — app in foreground _reloadData(); case AppLifecycleState.inactive: // Equivalent to onPause — partially obscured (iOS call, dialog) _pauseVideo(); case AppLifecycleState.paused: // Equivalent to onStop — app in background _saveState(); case AppLifecycleState.detached: // Equivalent to onDestroy — Flutter engine detached _cleanup(); case AppLifecycleState.hidden: // Added in Flutter 3.13 — between inactive and paused break; } } void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } }
Mapping: Android → Flutter
| Android Activity | Flutter AppLifecycleState |
|---|---|
text | text |
text | text |
text | text |
text | text |
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Saving data only in text | May not be called if process is killed | Save in text text |
| Heavy work in text | Blocks the incoming Activity from resuming | Move to text |
| Not unregistering receivers | Memory leak, duplicate callbacks | Unregister in text text |
| Not releasing camera in text | Camera locked — other apps can't use it | Always release in text |
| Forgetting rotation destroys Activity | State lost on screen rotation | Use text text |
| Calling text text | Activity flashes briefly before closing | Call text text |