Skip to main content

Kotlin Activity Lifecycle

Introduction

When developing Android applications with Kotlin, understanding the activity lifecycle is crucial for creating stable, responsive, and resource-efficient apps. The activity lifecycle refers to the different states an activity goes through from the time it's created until it's destroyed. Each transition between these states triggers specific callback methods that allow you to manage resources properly and create a seamless user experience.

In this guide, we'll explore:

  • What the Android activity lifecycle is
  • The different lifecycle callback methods
  • How to implement these callbacks in Kotlin
  • Best practices for managing resources throughout the lifecycle
  • Real-world examples to demonstrate practical applications

Understanding the Activity Lifecycle

An Android activity is a single, focused thing a user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI. As a user navigates through an app, activities are started, stopped, and destroyed.

Key Lifecycle States

  1. Created: The activity is initialized but not yet visible
  2. Started: The activity is visible but not in focus
  3. Resumed: The activity is visible and has focus
  4. Paused: The activity is partially visible but not in focus
  5. Stopped: The activity is not visible
  6. Destroyed: The activity is removed from memory

Lifecycle Callback Methods

Android provides several callback methods that allow you to know when the state of your activity changes:

onCreate()

This is called when the activity is first created. This is where you should:

  • Initialize essential components
  • Set the content view with setContentView()
  • Initialize UI elements
kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Initialize UI components
val myButton = findViewById<Button>(R.id.my_button)

// Setup listeners
myButton.setOnClickListener {
Toast.makeText(this, "Button clicked!", Toast.LENGTH_SHORT).show()
}
}

onStart()

Called when the activity becomes visible to the user.

kotlin
override fun onStart() {
super.onStart()
// The activity is about to become visible
Log.d("ActivityLifecycle", "onStart called")
}

onResume()

Called when the activity starts interacting with the user.

kotlin
override fun onResume() {
super.onResume()
// The activity is in the foreground and ready for user interaction
Log.d("ActivityLifecycle", "onResume called")
}

onPause()

Called when the system is about to resume another activity or when the activity loses focus.

kotlin
override fun onPause() {
super.onPause()
// The activity is no longer in the foreground
// Save data, stop animations or other operations that consume CPU
Log.d("ActivityLifecycle", "onPause called")
}

onStop()

Called when the activity is no longer visible to the user.

kotlin
override fun onStop() {
super.onStop()
// The activity is no longer visible
// Release resources that aren't needed while the activity isn't visible
Log.d("ActivityLifecycle", "onStop called")
}

onDestroy()

Called before the activity is destroyed.

kotlin
override fun onDestroy() {
super.onDestroy()
// The activity is about to be destroyed
// Clean up resources
Log.d("ActivityLifecycle", "onDestroy called")
}

onRestart()

Called after the activity has been stopped and before it is started again.

kotlin
override fun onRestart() {
super.onRestart()
// The activity is being restarted after being stopped
Log.d("ActivityLifecycle", "onRestart called")
}

Lifecycle Complete Implementation

Here's a complete example of an Activity class with all lifecycle methods implemented:

kotlin
class MainActivity : AppCompatActivity() {
private val TAG = "ActivityLifecycle"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "onCreate called")

// Initialize UI components
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
startActivity(Intent(this, SecondActivity::class.java))
}
}

override fun onStart() {
super.onStart()
Log.d(TAG, "onStart called")
}

override fun onResume() {
super.onResume()
Log.d(TAG, "onResume called")
}

override fun onPause() {
super.onPause()
Log.d(TAG, "onPause called")
}

override fun onStop() {
super.onStop()
Log.d(TAG, "onStop called")
}

override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy called")
}

override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestart called")
}
}

When you run this code and navigate through your app, you'll see the lifecycle logs in your Logcat window, showing the sequence of methods called:

D/ActivityLifecycle: onCreate called
D/ActivityLifecycle: onStart called
D/ActivityLifecycle: onResume called
// When pressing the home button
D/ActivityLifecycle: onPause called
D/ActivityLifecycle: onStop called
// When returning to the app
D/ActivityLifecycle: onRestart called
D/ActivityLifecycle: onStart called
D/ActivityLifecycle: onResume called
// When navigating to another activity
D/ActivityLifecycle: onPause called
// ... second activity lifecycle ...
// When pressing back
D/ActivityLifecycle: onRestart called
D/ActivityLifecycle: onStart called
D/ActivityLifecycle: onResume called

Practical Use Cases

1. Managing Resources

One of the most common uses of lifecycle methods is to properly manage resources:

kotlin
class CameraActivity : AppCompatActivity() {
private var camera: Camera? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
}

override fun onResume() {
super.onResume()
// Open camera when activity is in foreground
camera = Camera.open()
}

override fun onPause() {
super.onPause()
// Release camera when activity is not in foreground
camera?.release()
camera = null
}
}

2. Saving and Restoring State

kotlin
class NoteActivity : AppCompatActivity() {
private lateinit var noteEditText: EditText
private val NOTE_TEXT_KEY = "note_text"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_note)

noteEditText = findViewById(R.id.note_edit_text)

// Restore saved state if available
savedInstanceState?.getString(NOTE_TEXT_KEY)?.let {
noteEditText.setText(it)
}
}

override fun onSaveInstanceState(outState: Bundle) {
// Save the current note text before activity might be destroyed
outState.putString(NOTE_TEXT_KEY, noteEditText.text.toString())
super.onSaveInstanceState(outState)
}
}

3. Handling Configuration Changes

When a device configuration changes (like rotation), the activity is destroyed and recreated by default:

kotlin
class GameActivity : AppCompatActivity() {
private var gameScore = 0
private lateinit var scoreTextView: TextView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)

scoreTextView = findViewById(R.id.score_text)

savedInstanceState?.let {
// Restore score after configuration change
gameScore = it.getInt("SCORE", 0)
updateScoreDisplay()
}

findViewById<Button>(R.id.increment_button).setOnClickListener {
gameScore++
updateScoreDisplay()
}
}

private fun updateScoreDisplay() {
scoreTextView.text = "Score: $gameScore"
}

override fun onSaveInstanceState(outState: Bundle) {
// Save the current score
outState.putInt("SCORE", gameScore)
super.onSaveInstanceState(outState)
}
}

Using Lifecycle-Aware Components

Android Jetpack introduces LifecycleOwner and LifecycleObserver interfaces that make it easier to manage lifecycle events:

kotlin
class LocationManager(private val lifecycle: Lifecycle) : LifecycleObserver {

init {
lifecycle.addObserver(this)
}

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun startLocationUpdates() {
// Start location tracking
Log.d("LocationManager", "Starting location updates")
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun stopLocationUpdates() {
// Stop location tracking
Log.d("LocationManager", "Stopping location updates")
}
}

// In your Activity:
class MapActivity : AppCompatActivity() {
private lateinit var locationManager: LocationManager

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map)

// The LocationManager will automatically respond to lifecycle events
locationManager = LocationManager(lifecycle)
}
}

Common Pitfalls and Best Practices

  1. Memory Leaks: Avoid holding references to the Activity in long-lived objects
  2. ANR (Application Not Responding): Don't perform long operations in lifecycle methods
  3. Resource Management: Always release resources in the appropriate lifecycle method
  4. Background Work: Use appropriate components like WorkManager for background tasks
  5. Configuration Changes: Properly handle configuration changes to preserve user experience

Summary

The Android activity lifecycle provides a framework for managing the state of your app's activities. By understanding and properly implementing the lifecycle callbacks, you can:

  • Ensure your app behaves predictably when users navigate between activities
  • Manage system resources efficiently
  • Handle configuration changes smoothly
  • Prevent memory leaks and crashes
  • Create a responsive and robust user experience

The key to mastering the activity lifecycle is understanding the flow of states and knowing which operations are appropriate for each lifecycle callback.

Additional Resources

  1. Android Developers: Activity Lifecycle
  2. Android Jetpack: Lifecycle
  3. Codelabs: Android Activity Lifecycle

Exercises

  1. Create a simple app with two activities and log all lifecycle events. Navigate between the activities and observe the order of lifecycle method calls.
  2. Build an app that saves and restores its state during configuration changes (like rotation).
  3. Implement a timer app that continues counting accurately even when the app is paused and resumed.
  4. Create a camera app that properly handles camera resources throughout the activity lifecycle.
  5. Refactor an existing app to use Lifecycle-Aware Components for improved resource management.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)