Skip to main content

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
    }
}
Note: The lifecycle methods are called in a specific order, and each method should only handle its designated responsibilities to maintain app stability.

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!"
    }
}
Note: Always call 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")
    }
}
Note: These methods are part of the Android Activity lifecycle and are called when the activity transitions between visible and invisible states.

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")
    }
}
Note: These methods are part of the Android Activity lifecycle and should be used for managing resources efficiently.

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
    }
}
Note: It's important to cancel any ongoing background tasks or timers in 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>
Note: When 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)
    }
}
Note: The Bundle is automatically managed by the Android framework during configuration changes.
Warning: Do not store sensitive data in 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"))
}
Note: onRestoreInstanceState() is called after onStart(), but before onResume().
Warning: Do not store sensitive data in 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
        )
    }
}
Note: Lifecycle observers are automatically removed when the associated component is destroyed.

Key Points

  • LifecycleOwner is implemented by Activity and Fragment
  • LifecycleObserver is used to observe lifecycle events
  • @OnLifecycleEvent annotation 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" />
Note: The launch mode affects how the activity is launched and managed in the task stack.

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>
Note: The predictive back gesture is part of the new gesture navigation system introduced in Android 14.
Warning: Enabling this feature requires the app to support Android 14 (API level 34) or higher.

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
    }
}
Note: When using edge-to-edge display, ensure that your content does not overlap with system UI elements like the status bar or navigation bar. Use ViewCompat.setOnApplyWindowInsetsListener to handle insets properly.

Was this article helpful?