Managing Activity Lifecycle
1. Understanding Lifecycle States
| State | Description | Key Methods | Notes |
|---|---|---|---|
| CREATED | Activity is created but not yet visible | onCreate() |
Initial setup, inflate layout |
| STARTED | Activity is visible but not in focus | onStart() |
Prepare for interaction, load resources |
| RESUMED | Activity is in the foreground and interactive | onResume() |
Active user interaction, register listeners |
| PAUSED | Activity is partially obscured (e.g., dialog shown) | onPause() |
Save persistent state, release resources |
| STOPPED | Activity is no longer visible | onStop() |
Release heavy resources, save state |
| DESTROYED | Activity is being destroyed | onDestroy() |
Cleanup, release all resources |
Example: Lifecycle Callbacks in Kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
// Prepare for interaction
}
override fun onResume() {
super.onResume()
// Register listeners or start animations
}
override fun onPause() {
super.onPause()
// Save persistent state
}
override fun onStop() {
super.onStop()
// Release heavy resources
}
override fun onDestroy() {
super.onDestroy()
// Cleanup all resources
}
}
2. Implementing onCreate() Method
| Method | Description | Parameters | Return Type |
|---|---|---|---|
| onCreate() | Called when the activity is first created. This is where you should initialize the basic components of your activity. | savedInstanceState: Bundle? |
void |
Example: Implementing onCreate()
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize views and set up listeners
val textView = findViewById<TextView>(R.id.textView)
textView.text = "Hello, Android!"
}
}
super.onCreate(savedInstanceState) before making any changes to the activity's state.3. Implementing onStart() and onStop() Methods
| Method | Description | Usage |
|---|---|---|
| onStart() | Called when the activity becomes visible to the user | Use to initialize resources that are needed while the activity is visible |
| onStop() | Called when the activity is no longer visible to the user | Use to release resources that are not needed while the activity is not visible |
Example: Implementing onStart() and onStop()
class MainActivity : AppCompatActivity() {
private var isActivityVisible = false
override fun onStart() {
super.onStart()
isActivityVisible = true
Log.d("MainActivity", "Activity started")
}
override fun onStop() {
super.onStop()
isActivityVisible = false
Log.d("MainActivity", "Activity stopped")
}
}
4. Implementing onResume() and onPause() Methods
| Method | Description | Usage |
|---|---|---|
| onResume() | Called when the activity is about to start interacting with the user | Use to resume paused operations or initialize UI components |
| onPause() | Called when the activity is about to be paused | Use to save persistent data or release resources |
Example: Implementing onResume() and onPause()
class MainActivity : AppCompatActivity() {
private var isPaused = false
override fun onResume() {
super.onResume()
isPaused = false
// Resume any paused operations or UI updates
Log.d("Lifecycle", "Activity resumed")
}
override fun onPause() {
super.onPause()
isPaused = true
// Save data or release resources
Log.d("Lifecycle", "Activity paused")
}
}
5. Implementing onDestroy() Method
| Method | Description | Usage |
|---|---|---|
| onDestroy() | Called before the activity is destroyed. This is the final call that the activity receives. | Use to release resources, cancel background tasks, and perform cleanup operations. |
Example: Implementing onDestroy()
class MainActivity : AppCompatActivity() {
private var timer: Timer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
timer = Timer()
timer?.scheduleAtFixedRate(object : TimerTask() {
override fun run() {
// Background task
}
}, 0, 1000)
}
override fun onDestroy() {
super.onDestroy()
timer?.cancel()
timer = null
}
}
onDestroy() to prevent memory leaks.6. Handling Configuration Changes
| Property | Description | Notes |
|---|---|---|
| onConfigurationChanged() | Callback method invoked when configuration changes occur | Must be declared in manifest with configChanges attribute to receive the callback |
| configChanges | Manifest attribute to specify which configurations are handled by the app | Values: screenSize, orientation, keyboardHidden, locale, etc. |
Example: Handling Screen Rotation
class MainActivity : AppCompatActivity() {
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Handle landscape mode
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
// Handle portrait mode
}
}
}
Example: Manifest Declaration
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden">
</activity>
configChanges is specified, the system will not recreate the activity, and you must handle the changes manually.7. Saving Instance State
Android activities can be destroyed and recreated during configuration changes (like screen rotation) or when the system needs to free up memory. To preserve UI state, you must save and restore instance state using the onSaveInstanceState and onRestoreInstanceState methods.
| Method | Description | Usage |
|---|---|---|
| onSaveInstanceState(Bundle outState) | Saves the activity's state before it is destroyed. | Override to store UI state in a Bundle. |
| onRestoreInstanceState(Bundle savedInstanceState) | Restores the activity's state after it is recreated. | Override to retrieve UI state from a Bundle. |
Example: Saving and Restoring UI State
class MainActivity : AppCompatActivity() {
private var count = 0
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("count", count)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
count = savedInstanceState.getInt("count", 0)
}
}
Bundle is automatically managed by the Android framework during configuration changes.onSaveInstanceState as it is not encrypted and can be accessed by other apps.| Key | Type | Description |
|---|---|---|
| count | Int |
Current value of the counter. |
8. Restoring Instance State
When an Android activity is destroyed and recreated (e.g., due to screen rotation), the system can restore the activity's state using saved instance data.
| Method | Description | Usage |
|---|---|---|
| onSaveInstanceState() | Saves the activity's state to a Bundle |
Override to save UI state before destruction |
| onRestoreInstanceState() | Restores the activity's state from a Bundle |
Override to restore UI state after recreation |
Example: Saving and Restoring State
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("userInput", userInputEditText.text.toString())
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
userInputEditText.setText(savedInstanceState.getString("userInput"))
}
onRestoreInstanceState() is called after onStart(), but before onResume().Bundle as it may be persisted to disk.| State Key | Type | Description |
|---|---|---|
| android:windowSoftInputMode | String |
Controls soft input method behavior |
| android:configChanges | String |
Indicates which configuration changes are handled by the activity |
9. Using Lifecycle Observers
Android's Lifecycle component allows you to observe the lifecycle state of components like Activities and Fragments. Lifecycle-aware components can respond to lifecycle changes without explicitly managing the lifecycle state.
| Observer | Description | Usage |
|---|---|---|
| LifecycleOwner | Interface implemented by components that have a lifecycle (e.g., Activity, Fragment) | class MainActivity : AppCompatActivity(), LifecycleOwner |
| LifecycleObserver | Interface for components that observe lifecycle events | class MyObserver : LifecycleObserver |
| OnLifecycleEvent | Annotation to mark methods that respond to lifecycle events | @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onStart() |
Example: Implementing Lifecycle Observer
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Event.ON_START)
<span class="hljs-function>fun onStart() {
println("Activity started")
}
@OnLifecycleEvent(Event.ON_STOP)
<span class="hljs-function>fun onStop</span>() {
println("Activity stopped")
}
}
Example: Attaching Observer to Lifecycle
class MainActivity : AppCompatActivity() {
private val observer = MyObserver()
@Override
<span class="hljs-function>fun onCreate</span>(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager.registerFragmentLifecycleCallbacks(
object : FragmentLifecycleCallbacks() {
<span class="hljs-function>override fun onFragmentCreated</span>(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
f.lifecycle.addObserver(observer)
}
}, false
)
}
}
Key Points
LifecycleOwneris implemented byActivityandFragmentLifecycleObserveris used to observe lifecycle events@OnLifecycleEventannotation binds methods to lifecycle events- Observers are automatically cleaned up when the component is destroyed
10. Managing Activity Launch Modes
| Mode | Description | Behavior | Use Case |
|---|---|---|---|
| standard | Default launch mode. New instance created each time. | Creates a new instance every time the activity is launched. | General use when multiple instances are acceptable. |
| singleTop | Reuses existing instance if at top of stack. | If the activity is already at the top of the stack, it's reused; otherwise, a new instance is created. | When you want to reuse an activity if it's already at the top of the stack. |
| singleTask | Single instance in the task. | If an instance exists, it's brought to the foreground; otherwise, a new one is created. | When you want only one instance of the activity in any task. |
| singleInstance | Single instance in its own task. | A new task is created, and the activity is launched as the only instance in that task. | When you want a single instance of the activity and it should not be part of any other task. |
Example: Setting Launch Mode in Manifest
<activity
android:name=".MainActivity"
android:launchMode="singleTask" />
11. Implementing Predictive Back Gesture
| Property | Description | Notes |
|---|---|---|
| android:predictiveBackGestureEnabled | Enables or disables the predictive back gesture | Available from API level 34 (Android 14) |
Example: Enabling Predictive Back Gesture
<activity
android:name=".MainActivity"
android:predictiveBackGestureEnabled="true">
</activity>
12. Using Edge-to-Edge Display
Edge-to-edge display in Android allows apps to draw behind the system bars (status bar and navigation bar), creating a seamless immersive experience. This feature is particularly useful for media apps, games, and full-screen content.
| Property | Description | Values |
|---|---|---|
| windowDrawsSystemBarBackgrounds | Controls whether the window draws system bar backgrounds | true or false |
| fitsSystemWindows | Controls whether the view should adjust its padding to fit system windows | true or false |
Example: Enabling Edge-to-Edge Display
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Enable edge-to-edge display
WindowCompat.setDecorFitsSystemWindows(window, false)
}
}
Example: Setting Status Bar Color
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Set status bar color to transparent
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = Color.TRANSPARENT
}
}
ViewCompat.setOnApplyWindowInsetsListener to handle insets properly.