Android Passing Data Between Activities
A common requirement in Android development is to pass data from one Activity to another. For example, when a user selects an item from a list in one Activity, you might want to pass the details of that item to a new Activity that displays the item's details.
The primary way to pass data between Activities is by using the Intent
object that you use to start the new Activity. Intents have a built-in mechanism for carrying extra data in the form of key-value pairs.
Using Intent Extras:
The Intent
class provides a Bundle
object accessible through the getExtras()
method. This Bundle acts like a map (key-value pairs) where you can put various types of primitive data, objects, or arrays. You add data to the Intent before starting the target Activity and retrieve it in the target Activity.
1. Adding Data to the Intent (Sending Activity):
In the Activity where you are initiating the navigation, you add data to the Intent using the putExtra()
method. There are overloaded versions of putExtra()
for various data types.
// Assume you are navigating from MainActivity to DetailActivity
val intent = Intent(this, DetailActivity::class.java)
// Add a String
intent.putExtra("EXTRA_TITLE", "Product Title")
// Add an Int
intent.putExtra("EXTRA_PRICE", 1999) // Price in cents or similar
// Add a Boolean
intent.putExtra("EXTRA_IS_AVAILABLE", true)
// Add a Double
intent.putExtra("EXTRA_RATING", 4.5)
// Add a Parcelable object (more on this later)
// Assuming 'product' is an object that implements Parcelable
// intent.putExtra("EXTRA_PRODUCT", product)
// Add a Serializable object (more on this later)
// Assuming 'user' is an object that implements Serializable
// intent.putExtra("EXTRA_USER", user)
// Add a List of Strings
val tags = arrayListOf("electronics", "gadget")
intent.putStringArrayListExtra("EXTRA_TAGS", tags)
// Add an array of Integers
val quantities = intArrayOf(10, 5, 2)
intent.putExtra("EXTRA_QUANTITIES", quantities)
// Start the target Activity
startActivity(intent)
putExtra(key, value)
: Adds a key-value pair to the Intent's extras. The key is typically a String constant (often defined in the receiving activity or a separate constants file for clarity). The value can be of various primitive types, arrays of primitive types, or objects that implementParcelable
orSerializable
.
2. Retrieving Data from the Intent (Receiving Activity):
In the target Activity (the one you are navigating to), you retrieve the data from the Intent that started it. You typically do this in the onCreate()
method.
// In DetailActivity (the receiving Activity)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
// Get the Intent that started this Activity
val intent = intent
// Retrieve data using the corresponding get...Extra() methods and the same keys
val title = intent.getStringExtra("EXTRA_TITLE")
val price = intent.getIntExtra("EXTRA_PRICE", 0) // Provide a default value
val isAvailable = intent.getBooleanExtra("EXTRA_IS_AVAILABLE", false) // Provide a default value
val rating = intent.getDoubleExtra("EXTRA_RATING", 0.0) // Provide a default value
// Retrieve Parcelable object
// val product: Product? = intent.getParcelableExtra("EXTRA_PRODUCT")
// Retrieve Serializable object
// val user: User? = intent.getSerializableExtra("EXTRA_USER") as User? // Cast is needed
// Retrieve List of Strings
val tags: ArrayList<String>? = intent.getStringArrayListExtra("EXTRA_TAGS")
// Retrieve array of Integers
val quantities: IntArray? = intent.getIntArrayExtra("EXTRA_QUANTITIES")
// Now you can use the retrieved data (e.g., update UI elements)
val titleTextView: TextView = findViewById(R.id.titleTextView)
titleTextView.text = title
// ... display other data ...
}
intent
: Accesses the Intent that was used to start the current Activity.getStringExtra(key)
: Retrieves a String value. Returnsnull
if the key is not found.getIntExtra(key, defaultValue)
,getBooleanExtra(key, defaultValue)
,getDoubleExtra(key, defaultValue)
, etc.: Retrieve primitive values. You must provide a default value in case the key is not found in the Intent's extras.getParcelableExtra(key)
: Retrieves a Parcelable object.getSerializableExtra(key)
: Retrieves a Serializable object. Note that you usually need to cast the result.getStringArrayListExtra(key)
,getIntArrayExtra(key)
, etc.: Retrieve collections and arrays.
Passing Objects (Parcelable vs. Serializable):
When you need to pass complex objects between Activities, you have two main options:
1. Parcelable (Recommended for Android):
- Why: Parcelable is an Android-specific interface designed for efficient object serialization and deserialization. It's generally faster and more memory-efficient than Serializable.
- How: Your custom class needs to implement the
Parcelable
interface and provide the necessary methods for writing and reading its state to and from aParcel
. Android Studio provides a convenient way to implement Parcelable automatically.
import android.os.Parcel
import android.os.Parcelable
data class Product(val id: Int, val name: String, val price: Double) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString() ?: "", // Handle potential null string
parcel.readDouble()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(name)
parcel.writeDouble(price)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Product> {
override fun createFromParcel(parcel: Parcel): Product {
return Product(parcel)
}
override fun newArray(size: Int): Array<Product?> {
return arrayOfNulls(size)
}
}
}
Then, in your sending Activity:
val product = Product(1, "Smartphone", 699.99)
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("EXTRA_PRODUCT", product)
startActivity(intent)
And in your receiving Activity:
val product: Product? = intent.getParcelableExtra("EXTRA_PRODUCT")
// Use the product object
2. Serializable (Java Standard):
- Why: Serializable is a standard Java interface for object serialization. It's easier to implement (just add
: Serializable
to your class definition), but it's generally slower and creates more temporary objects than Parcelable. - When to use: Use Serializable for simpler objects or when you need to serialize objects for purposes other than inter-component communication within Android (e.g., saving to a file). Avoid it for performance-critical scenarios.
import java.io.Serializable
data class User(val id: Int, val username: String) : Serializable
Then, in your sending Activity:
val user = User(101, "johndoe")
val intent = Intent(this, ProfileActivity::class.java)
intent.putExtra("EXTRA_USER", user)
startActivity(intent)
And in your receiving Activity:
val user: User? = intent.getSerializableExtra("EXTRA_USER") as User?
// Use the user object
Note: Remember to cast the result of getSerializableExtra()
to your object type.
Best Practices for Passing Data:
- Use Constants for Keys: Define String constants for your extra keys (e.g.,
const val EXTRA_MESSAGE = "com.yourapp.EXTRA_MESSAGE"
) to avoid typos and make your code more readable and maintainable. - Provide Default Values: When retrieving primitive data types, always provide a default value to avoid potential crashes if the key is not found.
- Handle Nullability: When retrieving objects (Parcelable or Serializable), the result can be null if the key wasn't found or the data wasn't put correctly. Handle potential null values appropriately (e.g., using the safe call operator
?.
or null checks). -
Avoid Passing Large Amounts of Data: Intents are designed for passing relatively small amounts of data. Passing very large objects or large collections can lead to performance issues or even a
TransactionTooLargeException
. For large data, consider alternative methods like:- Storing data in a shared ViewModel (especially with Architecture Components).
- Saving data to a file or database and passing the file path or ID.
- Using a singleton object to hold the data temporarily.
- Prefer Parcelable over Serializable: For passing objects specifically between Android components, Parcelable is generally the better choice due to its performance benefits.
Key Takeaways for Passing Data:
- Use
Intent.putExtra(key, value)
to add data to an Intent. - Use the corresponding
intent.get...Extra(key, [defaultValue])
methods in the receiving Activity to retrieve the data. - Define constants for your extra keys.
- Handle nullability and provide default values when retrieving data.
- For passing custom objects, implement
Parcelable
(recommended) orSerializable
. - Avoid passing excessively large amounts of data via Intents.
Effectively passing data between activities is a fundamental skill for building interconnected and data-driven Android applications. By using Intent extras and choosing the appropriate serialization method for objects, you can ensure smooth data flow within your app.