Mastering Intents: Passing Data Between Activities in Kotlin for Android XML

In Android development, Activities are the building blocks of user interfaces. Passing data between activities is a common requirement, especially when dealing with complex user flows. Intents are the primary mechanism for facilitating this communication. This blog post will explore how to efficiently pass data between activities using Intents in Kotlin with XML layouts.

What are Intents in Android?

An Intent is a messaging object that you can use to request an action from another app component. Intents are primarily used to start activities, services, and broadcast receivers. They can also carry data across these components, enabling different parts of your application or different applications to communicate with each other.

Why Pass Data Between Activities?

Passing data between activities allows you to:

  • Maintain state and context as users navigate through different screens.
  • Send user input from one screen to another for processing.
  • Update UI elements based on data from previous activities.
  • Facilitate inter-app communication, where data can be shared between different Android apps.

How to Pass Data Between Activities Using Intents in Kotlin

Let’s go through the steps of passing data between activities using Intents in a Kotlin-based Android project with XML layouts.

Step 1: Create a New Android Project

If you haven’t already, create a new Android project in Android Studio with Kotlin support.

Step 2: Design the Layouts (XML)

First, create two activities: MainActivity and SecondActivity. Define the layout for each activity in their respective XML files.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editTextData"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Enter Data to Pass"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <Button
        android:id="@+id/buttonSendData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Data"
        app:layout_constraintTop_toBottomOf="@+id/editTextData"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".SecondActivity">

    <TextView
        android:id="@+id/textViewReceivedData"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:text="Received Data:"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 3: Implement MainActivity.kt

In MainActivity.kt, set up the Intent to send data to SecondActivity.


import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val editTextData: EditText = findViewById(R.id.editTextData)
        val buttonSendData: Button = findViewById(R.id.buttonSendData)

        buttonSendData.setOnClickListener {
            val dataToSend = editTextData.text.toString()

            val intent = Intent(this, SecondActivity::class.java)
            intent.putExtra("data", dataToSend)
            startActivity(intent)
        }
    }
}

In this code:

  • An EditText field allows users to input data.
  • When the button is clicked, it retrieves the text from the EditText.
  • An Intent is created, specifying SecondActivity as the target.
  • The putExtra() method adds the data to the Intent, using the key “data”.
  • startActivity(intent) starts the SecondActivity.

Step 4: Implement SecondActivity.kt

In SecondActivity.kt, retrieve the data passed from MainActivity and display it.


import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        val textViewReceivedData: TextView = findViewById(R.id.textViewReceivedData)

        val receivedData = intent.getStringExtra("data")
        textViewReceivedData.text = "Received Data: $receivedData"
    }
}

In this code:

  • The intent.getStringExtra("data") method retrieves the data associated with the key “data”.
  • The retrieved data is then displayed in a TextView.

Passing Complex Data (Parcelable and Serializable)

For more complex data types, such as custom objects, you can use either Parcelable or Serializable.

Using Parcelable

Parcelable is an Android-specific interface that provides a highly efficient way to serialize and deserialize objects.

Step 1: Implement Parcelable

Create a data class and implement the Parcelable interface:


import android.os.Parcel
import android.os.Parcelable

data class User(val name: String, val age: Int) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString()!!,
        parcel.readInt()
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(this.name)
        parcel.writeInt(this.age)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<User> {
        override fun createFromParcel(parcel: Parcel): User {
            return User(parcel)
        }

        override fun newArray(size: Int): Array<User?> {
            return arrayOfNulls(size)
        }
    }
}
Step 2: Send the Parcelable Object

val user = User("John Doe", 30)
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("user", user)
startActivity(intent)
Step 3: Receive the Parcelable Object

val user = intent.getParcelableExtra<User>("user")
val receivedData = "Received User: Name = ${user?.name}, Age = ${user?.age}"
textViewReceivedData.text = "Received Data: $receivedData"

Using Serializable

Serializable is a standard Java interface that allows objects to be converted into a byte stream. It’s simpler to implement but less efficient than Parcelable.

Step 1: Implement Serializable

Create a data class and implement the Serializable interface:


import java.io.Serializable

data class User(val name: String, val age: Int) : Serializable
Step 2: Send the Serializable Object

val user = User("Jane Doe", 25)
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("user", user)
startActivity(intent)
Step 3: Receive the Serializable Object

val user = intent.getSerializableExtra("user") as? User
val receivedData = "Received User: Name = ${user?.name}, Age = ${user?.age}"
textViewReceivedData.text = "Received Data: $receivedData"

Conclusion

Passing data between activities using Intents in Kotlin is fundamental to Android development. Simple data can be passed directly using putExtra() and retrieved with getStringExtra(). For complex data, implementing Parcelable or Serializable allows you to pass objects efficiently. By understanding these methods, you can effectively manage data flow and enhance the user experience in your Android applications.