Exploring the Android Activity Lifecycle
Course: Android App Development
Topic: Exploring the Android Activity Lifecycle
Course Link: Android App Development Training – JustAcademy
Demo Link: Register for a Course Demo
JustAcademy Homepage: Visit JustAcademy
1. Introduction to the Android Activity Lifecycle
The Android Activity Lifecycle describes the different states an Android Activity passes through from the time it is created until it is destroyed. An Activity represents a single screen or focused interaction area in an Android application, such as a login screen, product details screen, profile page, or settings screen.
Android manages Activity lifecycle transitions according to user actions, system events, navigation, configuration changes, and available system resources. Developers implement lifecycle callback methods to initialize the screen, prepare resources, pause ongoing work, save necessary state, and release resources at the appropriate time.
Understanding the Activity Lifecycle is essential for building Android applications that behave correctly when users switch applications, rotate their devices, open another screen, lock the device, or return to an existing screen.
Learning Objectives
- Understand the meaning and purpose of the Activity Lifecycle.
- Learn the roles of
onCreate(), onStart(), onResume(), onPause(), onStop(), and onDestroy().
- Understand the purpose of
onRestart() and onSaveInstanceState().
- Trace lifecycle callbacks during common Android user interactions.
- Learn how to preserve and restore screen state.
- Understand configuration changes, Activity recreation, and process termination.
- Apply lifecycle best practices to practical Kotlin Android applications.
2. What Is an Android Activity?
An Activity is an Android application component that provides a user-facing interaction point. It typically manages a screen, coordinates user interactions, and connects the user interface with application logic.
For example, an e-commerce application may contain separate Activities for authentication, product browsing, and order confirmation. Modern Android applications may instead use a single Activity with multiple destinations managed by a navigation framework, but the Activity Lifecycle remains important.
Responsibilities of an Activity
- Initialize the screen and its required objects.
- Connect the user interface to application data.
- Respond to user input and navigation events.
- Coordinate with ViewModels and lifecycle-aware components.
- Manage resources according to visibility and foreground state.
- Save and restore appropriate temporary interface state.
3. Understanding the Main Lifecycle States
An Activity moves between lifecycle states as Android responds to changes in the application's environment. Each callback provides an opportunity to perform work appropriate to the new state.
| Callback |
Purpose |
Typical Responsibility |
onCreate() |
Initial Activity creation |
Initialize the screen, set up views, and prepare required objects. |
onStart() |
Activity becomes visible |
Prepare UI-related resources and start visibility-dependent work. |
onResume() |
Activity enters the foreground interaction state |
Start functionality that requires active user interaction. |
onPause() |
Activity loses foreground focus |
Pause short-lived foreground work and release resources that are no longer needed. |
onStop() |
Activity is no longer visible |
Stop visibility-dependent work and release resources that are not needed in the background. |
onRestart() |
Stopped Activity is about to start again |
Prepare for the Activity to become visible again. |
onDestroy() |
Activity instance is being destroyed |
Perform final instance-specific cleanup. |
These callbacks do not all execute every time a user interacts with an app. The exact sequence depends on what happens, whether the Activity remains visible, and whether Android recreates or finishes it.
4. Understanding onCreate()
The onCreate() callback is called when Android creates a new Activity instance. It is generally the first lifecycle callback developers implement for initial screen setup.
Common Uses
- Set the Activity's layout using
setContentView() in a View-based application.
- Initialize view references and event listeners.
- Prepare adapters and screen-level objects.
- Obtain a ViewModel.
- Restore temporary UI state when available.
- Read the Intent that launched the Activity.
Kotlin Example
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("ActivityLifecycle", "onCreate called")
}
}
In this example, Android creates the Activity, the superclass initialization runs, and the layout is attached to the Activity. The log statement helps developers observe the callback during testing.
Understanding savedInstanceState
The savedInstanceState parameter is a Bundle? that may contain previously saved state. It is commonly null when the Activity is being created without saved instance state and non-null when Android has saved state available to restore.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState != null) {
// Restore small pieces of previously saved UI state.
} else {
// Initialize the screen for a fresh instance.
}
}
Do not assume that every Activity recreation will have useful saved state. Also, avoid placing large objects or entire application datasets inside a Bundle. Use suitable persistence mechanisms for data that must survive process death or application restarts.
5. Understanding onStart()
The onStart() callback is called when an Activity becomes visible to the user. The Activity may be visible without having full input focus, depending on the current window configuration.
Common Uses
- Register listeners that should be active while the Activity is visible.
- Refresh information that needs to be current when the screen appears.
- Start visibility-dependent UI updates.
- Prepare components that should operate while the Activity is visible.
override fun onStart() {
super.onStart()
Log.d("ActivityLifecycle", "onStart called")
}
The callback may run more than once during the lifetime of the same Activity instance. For example, when a user returns to an Activity that was stopped, Android normally invokes onRestart() followed by onStart().
6. Understanding onResume()
The onResume() callback indicates that the Activity has entered the resumed state and is ready to interact with the user. This is an appropriate place to start functionality that requires foreground interaction or active focus.
Common Uses
- Resume a paused animation or interactive experience.
- Start a camera preview when appropriate permissions and lifecycle rules are satisfied.
- Resume foreground-only sensors or other interactive resources.
- Refresh UI behavior that must be active while the user interacts with the screen.
override fun onResume() {
super.onResume()
Log.d("ActivityLifecycle", "onResume called")
}
The Activity may return to the resumed state several times without being recreated. Therefore, foreground resources should be started and stopped in a balanced way to prevent duplicate listeners, camera sessions, or other resource leaks.
7. Understanding onPause()
The onPause() callback is called when the Activity loses its resumed state. This often occurs when another Activity takes focus, a system interruption occurs, or the user begins navigating away.
A paused Activity may still be visible, particularly in multi-window scenarios. Therefore, onPause() does not necessarily mean that the screen is completely hidden or that the Activity will be destroyed.
Common Uses
- Pause animations or interactions that should not continue without foreground focus.
- Pause a camera preview or similar foreground-only feature.
- Release resources that are needed only while the Activity is resumed.
- Temporarily stop work that should resume when the user returns.
override fun onPause() {
super.onPause()
Log.d("ActivityLifecycle", "onPause called")
}
Important: Keep onPause() fast. Do not depend on it to finish lengthy network requests, database transactions, or large save operations. The callback is intended for brief transition-related work.
8. Understanding onStop()
The onStop() callback is called when the Activity is no longer visible to the user. This may happen when another Activity fully covers it, when the user navigates away, or when the Activity is finishing.
Common Uses
- Stop updates that are unnecessary while the screen is hidden.
- Unregister listeners registered for the visible lifetime.
- Pause expensive UI-related operations.
- Release resources that are not required while the Activity is invisible.
- Coordinate saving important data through an appropriate repository or persistence layer.
override fun onStop() {
super.onStop()
Log.d("ActivityLifecycle", "onStop called")
}
Do not treat onStop() as a guaranteed final callback before process termination. Android can terminate an application's process under resource pressure without calling every cleanup callback. Important user data should be saved proactively.
9. Understanding onRestart()
The onRestart() callback is called when an Activity that was stopped is about to start again. It is normally followed by onStart() and then onResume() if the Activity returns to the resumed state.
override fun onRestart() {
super.onRestart()
Log.d("ActivityLifecycle", "onRestart called")
}
For example, when a user opens another full-screen Activity and then returns to the previous one, the previous Activity may go through onRestart(), onStart(), and onResume().
Use this callback only when there is a specific restart-related task. Many applications can handle the required work in onStart() or through lifecycle-aware components instead.
10. Understanding onDestroy()
The onDestroy() callback is called before an Activity instance is destroyed. It may be invoked when the Activity finishes or when Android recreates it because of a configuration change, such as a device rotation.
Common Uses
- Release remaining resources owned by the Activity instance.
- Remove callbacks or references that the Activity itself registered and must clean up.
- Perform final instance-specific cleanup not already handled in earlier lifecycle callbacks.
override fun onDestroy() {
super.onDestroy()
Log.d("ActivityLifecycle", "onDestroy called")
}
Important: Do not use onDestroy() as the only place to save essential user data. The system may terminate the process without calling it. Use persistent storage and appropriate state-saving mechanisms for data that must survive beyond the Activity instance.
11. Complete Activity Lifecycle Flow
The following simplified flows illustrate common lifecycle transitions.
Launching an Activity for the First Time
onCreate()
↓
onStart()
↓
onResume()
The Activity is created, becomes visible, and enters the resumed state.
Leaving an Activity That Becomes Fully Hidden
onPause()
↓
onStop()
The Activity loses foreground focus and then becomes invisible. It may remain in memory, or the system may later destroy its process.
Returning to a Stopped Activity
onRestart()
↓
onStart()
↓
onResume()
The existing Activity instance returns to the visible and resumed states when Android retains it and the user navigates back.
Finishing an Activity
onPause()
↓
onStop()
↓
onDestroy()
This is a common finishing sequence when the Activity was resumed and then completely removed. Exact callbacks depend on the Activity's current state and the reason for its transition.
12. Logging Lifecycle Callbacks in Kotlin
Logging is a practical way to understand lifecycle behavior while testing an Android application. Add log statements to callbacks, launch the application, navigate between screens, rotate the device, and observe the output in Android Studio's Logcat.
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
class LifecycleActivity : AppCompatActivity() {
private val tag = "LifecycleActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(tag, "onCreate")
}
override fun onStart() {
super.onStart()
Log.d(tag, "onStart")
}
override fun onResume() {
super.onResume()
Log.d(tag, "onResume")
}
override fun onPause() {
super.onPause()
Log.d(tag, "onPause")
}
override fun onStop() {
super.onStop()
Log.d(tag, "onStop")
}
override fun onRestart() {
super.onRestart()
Log.d(tag, "onRestart")
}
override fun onDestroy() {
super.onDestroy()
Log.d(tag, "onDestroy")
}
}
When reading logs, remember that callback sequences can differ based on whether an Activity is being covered, restarted, recreated, or finished. Use the logs to observe actual behavior on the emulator or device rather than assuming every action produces the same sequence.
13. Saving and Restoring Activity State
Users expect an application to preserve useful information when they rotate a device, switch applications, or return to a screen. Android provides saved instance state for small amounts of temporary UI data, while persistent storage is used for information that must survive longer periods.
Saving Small Values with onSaveInstanceState()
private var counter = 0
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt("counter_value", counter)
super.onSaveInstanceState(outState)
}
Restoring Values in onCreate()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
counter = savedInstanceState?.getInt("counter_value") ?: 0
}
This example saves a small integer and restores it when saved state is available. In a real application, the value would also need to be connected to the UI and updated whenever the user changes it.
Choosing the Right State Storage
| Mechanism |
Best Use |
Limitation |
onSaveInstanceState() and Bundle |
Small, temporary UI state needed for Activity recreation. |
Not intended for large objects or permanent application data. |
ViewModel |
UI-related data that should survive configuration changes. |
Does not by itself guarantee survival after process death. |
SavedStateHandle |
Small restorable state associated with a ViewModel. |
Designed for state restoration, not as a replacement for a database. |
| Room or another database |
Structured data that should persist across sessions. |
Requires data modeling and storage management. |
| DataStore or preferences |
Small persistent settings and key-value information. |
Not intended for complex relational datasets. |
14. Understanding Configuration Changes
A configuration change occurs when an environmental setting affecting the application changes. Common examples include device rotation, window-size changes, and certain display or language changes.
Depending on the configuration and the application's handling, Android may destroy the current Activity instance and create a new one. When this happens, lifecycle callbacks such as onPause(), onStop(), and onDestroy() may be followed by a new instance's onCreate(), onStart(), and onResume().
Why Configuration Changes Matter
- Views and Activity fields belong to a particular Activity instance.
- Data stored only in ordinary Activity fields can be lost when the instance is recreated.
- Repeated initialization can accidentally start duplicate work if cleanup is incorrect.
- The UI should adapt to the new configuration without losing important user progress.
Use a ViewModel for appropriate screen-related data that should survive configuration changes, and use saved state or persistent storage when data must also survive process recreation.
15. Activity Lifecycle and ViewModel
A ViewModel separates UI-related data from the Activity instance. When Android recreates an Activity for a configuration change, the ViewModel associated with that Activity's ViewModel store can be retained and reused by the new Activity instance.
import androidx.lifecycle.ViewModel
class CounterViewModel : ViewModel() {
var count: Int = 0
private set
fun increment() {
count++
}
}
An Activity can obtain this ViewModel using the appropriate AndroidX ViewModel APIs. This helps keep state across configuration changes without relying solely on Activity fields.
A regular ViewModel does not automatically survive process death. For values that must be restored after process recreation, consider SavedStateHandle or persistent storage, depending on the type and importance of the data.
16. Lifecycle-Aware Components
Lifecycle-aware components can observe lifecycle events and manage their own work according to the Activity or other LifecycleOwner's state. This helps reduce the amount of lifecycle-specific code placed directly inside an Activity.
AndroidX Lifecycle APIs and coroutine integrations provide ways to start work only while the UI is in a suitable state. For example, a coroutine launched with repeatOnLifecycle can collect a flow while the Activity is at least in the Started state and stop collection when it falls below that state.
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// Collect UI data or perform lifecycle-bound work here.
// The block is cancelled when the Activity falls below STARTED.
}
}
}
}
This is a structural example showing lifecycle-aware coroutine usage. In a complete implementation, place the required Flow collection or other suspendable work inside the block. Lifecycle-aware APIs do not replace appropriate error handling or persistence.
17. Activity Lifecycle in Common Scenarios
| Scenario |
Possible Lifecycle Behavior |
Developer Consideration |
| App launched for the first time |
onCreate(), onStart(), onResume() |
Initialize the screen and prepare interactive resources. |
| User opens another full-screen Activity |
Current Activity may receive onPause() and onStop(). |
Pause foreground work and stop hidden-screen work. |
| User returns to a stopped Activity |
onRestart(), onStart(), onResume() |
Restart appropriate visibility- and foreground-dependent work. |
| User rotates the device |
The Activity may be recreated, depending on configuration handling. |
Preserve state and avoid duplicate resource initialization. |
| User opens a partly transparent screen |
The underlying Activity may be paused but still visible. |
Do not assume that pause means complete invisibility. |
| Activity finishes |
It commonly passes through pause and stop before destruction. |
Release instance-specific resources appropriately. |
| System terminates the process |
Not every lifecycle callback is guaranteed to run. |
Persist important data before it is at risk of being lost. |
18. Common Lifecycle Mistakes
| Mistake |
Why It Is a Problem |
Better Approach |
Putting all initialization in onResume() |
The method may run repeatedly, causing duplicate setup. |
Initialize instance-level objects in onCreate() and match resources to their required lifecycle. |
Performing lengthy operations in onPause() |
The transition can be delayed or the operation may not finish. |
Keep pause work brief and move longer tasks to appropriate background or persistence mechanisms. |
Saving important data only in onDestroy() |
The process may terminate without that callback. |
Save important changes proactively and use persistent storage. |
Assuming onStop() means the Activity is destroyed |
A stopped Activity may later be restarted. |
Separate visibility-related cleanup from final instance cleanup. |
| Ignoring configuration changes |
Temporary screen data may disappear during recreation. |
Use ViewModel, saved instance state, and persistent storage as appropriate. |
| Forgetting to unregister listeners |
Resources may leak or callbacks may occur when they are no longer needed. |
Register and unregister according to the relevant lifecycle interval. |
| Assuming callbacks always occur in one fixed sequence |
Different user actions and system events produce different transitions. |
Test realistic scenarios and use lifecycle-aware APIs. |
19. Best Practices for Managing the Activity Lifecycle
- Call the superclass implementation in lifecycle overrides where required, and follow the framework's documented behavior.
- Keep lifecycle callbacks short and avoid blocking the main thread.
- Match resource acquisition and release to the period in which each resource is needed.
- Use ViewModels to hold appropriate UI state across configuration changes.
- Use saved instance state for small, temporary values that need restoration.
- Persist important user data before it can be lost rather than relying on final callbacks.
- Use lifecycle-aware components and coroutine APIs to reduce manual lifecycle management.
- Test navigation, backgrounding, rotation, multi-window behavior, and process recreation.
- Use Logcat and Android Studio debugging tools to investigate unexpected transitions.
- Do not assume that an Activity remaining in memory means its process will remain alive indefinitely.
20. Practical Exercise: Build a Lifecycle Logger
Objective: Create a simple Android application that records lifecycle callbacks and helps you understand how Activity state changes in response to user actions.
Steps
- Create a new Android project using Kotlin in Android Studio.
- Add log statements to the seven main lifecycle callbacks.
- Run the app and filter Logcat using the tag
LifecycleActivity.
- Press the Home button and observe the callbacks.
- Return to the application and record the callbacks that occur.
- Open another full-screen Activity and return to the original screen.
- Rotate the device and observe whether the Activity is recreated.
- Finish the Activity and observe its final callbacks.
Expected Learning Outcome
You should be able to explain which callbacks correspond to initial creation, visibility, foreground interaction, pausing, stopping, restarting, and destruction. You should also understand why the exact callback sequence depends on the situation.
21. Interview Questions and Answers
Q1. What is the Android Activity Lifecycle?
It is the sequence of states and callback methods through which an Activity moves as it is created, displayed, paused, stopped, restarted, or destroyed.
Q2. What is the purpose of onCreate()?
onCreate() initializes a newly created Activity instance. Developers commonly set up the UI, initialize instance-level objects, and restore available saved state.
Q3. What is the difference between onStart() and onResume()?
onStart() indicates that the Activity is becoming visible. onResume() indicates that it has entered the resumed state and is ready for foreground interaction.
Q4. Does onPause() mean the Activity is destroyed?
No. The Activity may remain in memory and may even remain partly visible. It can return to the resumed state without being recreated.
Q5. When is onStop() called?
onStop() is called when the Activity is no longer visible to the user. It is an appropriate point to stop work that is unnecessary while the screen is hidden.
Q6. What is the purpose of onRestart()?
onRestart() is called when a stopped Activity is about to start again. It is normally followed by onStart().
Q7. When is onDestroy() called?
It is called before an Activity instance is destroyed, for example when the Activity finishes or is recreated after a configuration change. It is not guaranteed to run before process termination.
Q8. What is savedInstanceState?
It is a nullable Bundle that may contain small pieces of previously saved Activity state, allowing the Activity to restore temporary UI information when recreated.
Q9. What is a configuration change?
It is a change to the environment that affects how an application should be displayed or behave, such as device rotation or a window-size change. It may cause Activity recreation.
Q10. How does a ViewModel help with Activity recreation?
A ViewModel retains appropriate UI-related data across configuration changes, allowing a recreated Activity to reuse that state. A regular ViewModel alone does not guarantee survival after process death.
Q11. Why should long-running work not be performed in onPause()?
The callback should complete quickly. Long operations may delay transitions or fail to complete. Use appropriate background work and persistence mechanisms for operations that need more time.
Q12. Is onDestroy() guaranteed to be called?
No. Android can terminate the application's process without calling every lifecycle callback. Critical data should be persisted proactively.
Q13. What happens when a user returns to a stopped Activity?
If Android retains the Activity instance, it typically calls onRestart(), onStart(), and onResume().
Q14. How can developers debug lifecycle behavior?
They can add log statements to callback methods and observe the sequence in Android Studio's Logcat while testing different user actions and system events.
Q15. What are lifecycle-aware components?
They are components that observe lifecycle states and events so they can start, stop, or manage work according to the lifecycle of an Activity or another LifecycleOwner.
22. Quick Revision Checklist
- Understand the purpose of each Activity lifecycle callback.
- Know the typical startup sequence:
onCreate(), onStart(), onResume().
- Distinguish between paused and stopped states.
- Know when
onRestart() is used.
- Understand why
onDestroy() is not a reliable sole location for saving data.
- Know how to save and restore small values with a Bundle.
- Understand how ViewModel helps with configuration changes.
- Know the difference between temporary UI state and persistent application data.
- Use lifecycle-aware APIs where appropriate.
- Practice reading lifecycle logs in Android Studio.
23. Learning Resources
24. Conclusion
The Android Activity Lifecycle is a fundamental concept for building stable and responsive mobile applications. Each callback serves a different purpose, from initializing the Activity and preparing the UI to pausing foreground work, releasing hidden-screen resources, and cleaning up an Activity instance.
By understanding lifecycle transitions, preserving UI state appropriately, using ViewModels and lifecycle-aware components, and avoiding assumptions about process lifetime, developers can create Android applications that handle navigation, configuration changes, and interruptions more reliably.
Practice the lifecycle logger exercise and observe callback sequences on an emulator or physical device. Hands-on testing is one of the most effective ways to understand how Android manages Activity instances throughout an application's lifetime.