Intents & Intent Filters — Navigating Between Screens
Intents are the glue that connects different components in Android. They allow you to start activities, start services, broadcast events, and send data between components. In simple terms, an Intent is a message that tells Android what you want to do.
1. What is an Intent?
An Intent is an object that describes an operation to be performed. It can be used to:
- Start an Activity — Navigate to a new screen
- Start a Service — Perform background operations
- Send a Broadcast — Notify other components about events
- Pass Data — Send data between components
| Intent Type | Description | Use Case |
|---|---|---|
| Explicit Intent | Specifies the exact component to be called | Navigating within your own app |
| Implicit Intent | Describes the action to be performed | Opening a URL, sharing content, taking a photo |
2. Explicit Intents — Navigating Within Your App
An Explicit Intent directly specifies the component (Activity, Service, or BroadcastReceiver) that should handle the intent. It's used when you know exactly which component you want to start.
Basic Explicit Intent
// In MainActivity.kt — Start SecondActivity
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
Passing Data with Explicit Intents
// Sending data — MainActivity.kt
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra("USER_NAME", "John Doe")
putExtra("USER_AGE", 25)
putExtra("IS_ACTIVE", true)
}
startActivity(intent)
// Receiving data — SecondActivity.kt
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val userName = intent.getStringExtra("USER_NAME") ?: "Unknown"
val userAge = intent.getIntExtra("USER_AGE", 0)
val isActive = intent.getBooleanExtra("IS_ACTIVE", false)
Log.d("SecondActivity", "Name: $userName, Age: $userAge, Active: $isActive")
}
}
Passing Serializable Data
// User data class — must implement Serializable
data class User(
val name: String,
val email: String,
val age: Int
) : Serializable
// Sending Serializable object
val user = User("John Doe", "john@example.com", 25)
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra("USER_OBJECT", user)
}
startActivity(intent)
// Receiving Serializable object
val user = intent.getSerializableExtra("USER_OBJECT") as? User
@Parcelize annotation makes this easy.
Getting Results Back from an Activity
// Starting activity for result — MainActivity.kt
val intent = Intent(this, SecondActivity::class.java)
startActivityForResult(intent, REQUEST_CODE)
// In SecondActivity.kt — Sending result back
val resultIntent = Intent().apply {
putExtra("RESULT_DATA", "Data from SecondActivity")
}
setResult(Activity.RESULT_OK, resultIntent)
finish()
// Receiving result — MainActivity.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val result = data?.getStringExtra("RESULT_DATA")
Log.d("MainActivity", "Result: $result")
}
}
startActivityForResult() is deprecated in favor of the Activity Result API (introduced in AndroidX). Use ActivityResultLauncher for new projects.
Modern Approach — Activity Result API
// Register the launcher — MainActivity.kt
private val resultLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data?.getStringExtra("RESULT_DATA")
Log.d("MainActivity", "Result: $data")
}
}
// Launch the activity
val intent = Intent(this, SecondActivity::class.java)
resultLauncher.launch(intent)
3. Implicit Intents — Interacting with Other Apps
An Implicit Intent doesn't specify a specific component. Instead, it declares an action to be performed, and the Android system finds the best component to handle it.
Opening a URL
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://google.com"))
startActivity(intent)
Opening a Phone Dialer
val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:+919999999999"))
startActivity(intent)
Making a Phone Call (Requires Permission)
// Add permission in AndroidManifest.xml
// <uses-permission android:name="android.permission.CALL_PHONE" />
val intent = Intent(Intent.ACTION_CALL, Uri.parse("tel:+919999999999"))
startActivity(intent)
Opening a Map Location
val intent = Intent(
Intent.ACTION_VIEW,
Uri.parse("geo:28.6139,77.2090?q=New+Delhi")
)
startActivity(intent)
Sharing Content (Share Sheet)
val sendIntent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "Check out this amazing app!")
}
startActivity(Intent.createChooser(sendIntent, "Share via"))
Opening an Email Client
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:")
putExtra(Intent.EXTRA_EMAIL, arrayOf("recipient@example.com"))
putExtra(Intent.EXTRA_SUBJECT, "App Feedback")
putExtra(Intent.EXTRA_TEXT, "Hello, I would like to provide feedback...")
}
startActivity(intent)
Taking a Photo (Implicit Intent)
// Requires file provider setup for Android 7.0+
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(packageManager) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
// Handle result
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
val imageBitmap = data?.extras?.get("data") as? Bitmap
imageView.setImageBitmap(imageBitmap)
}
}
4. Intent Filters — Declaring Capabilities
Intent Filters are declared in the AndroidManifest.xml file to specify what types of implicit intents an activity can handle. This is how your app can respond to system-wide actions like sharing.
Declaring an Intent Filter
<activity android:name=".MainActivity">
<!-- This activity is the launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- This activity can handle URL links -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="example.com" />
</intent-filter>
<!-- This activity can receive shared text -->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Handling Implicit Intents in Your Activity
// MainActivity.kt — Handle incoming intent
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Check if this activity was launched by an implicit intent
intent?.let { incomingIntent ->
when (incomingIntent.action) {
Intent.ACTION_VIEW -> {
val data = incomingIntent.data
Log.d("MainActivity", "Data: $data")
// Handle URL or data
}
Intent.ACTION_SEND -> {
val sharedText = incomingIntent.getStringExtra(Intent.EXTRA_TEXT)
Log.d("MainActivity", "Shared Text: $sharedText")
// Handle shared content
}
}
}
}
5. Common Intent Actions
| Action | Description | Example |
|---|---|---|
ACTION_VIEW | View data (URL, URI) | Intent(Intent.ACTION_VIEW, Uri.parse("https://..."))) |
ACTION_DIAL | Open dialer with a phone number | Intent(Intent.ACTION_DIAL, Uri.parse("tel:123")) |
ACTION_CALL | Make a phone call | Intent(Intent.ACTION_CALL, Uri.parse("tel:123")) |
ACTION_SEND | Share data | Intent(Intent.ACTION_SEND).putExtra(...) |
ACTION_SENDTO | Send to a specific recipient | Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:")) |
ACTION_PICK | Pick data (e.g., contact, image) | Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI) |
ACTION_GET_CONTENT | Get content (file picker) | Intent(Intent.ACTION_GET_CONTENT).setType("image/*") |
ACTION_WEB_SEARCH | Perform a web search | Intent(Intent.ACTION_WEB_SEARCH).putExtra(SearchManager.QUERY, "query") |
ACTION_SET_ALARM | Set an alarm | Intent(AlarmClock.ACTION_SET_ALARM) |
6. Common Pitfalls & Solutions
Pitfall 1: Not checking if an implicit intent can be handled
Problem: If no app can handle your intent, your app will crash.
Solution: Always check with resolveActivity() before starting an implicit intent.
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://google.com"))
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
Toast.makeText(this, "No app can handle this action", Toast.LENGTH_SHORT).show()
}
Pitfall 2: Passing large data objects
Problem: Intents have a size limit (~1MB). Passing large data can crash your app.
Solution: Use shared ViewModel or singleton for large data, or pass only an ID and fetch the data in the destination activity.
Pitfall 3: Not using the correct data type for extras
Problem: Retrieving extras with the wrong type (e.g., getStringExtra on an int) returns null.
Solution: Use the correct getter method and provide a default value:
val name = intent.getStringExtra("NAME") ?: "Unknown"
val age = intent.getIntExtra("AGE", 0)
7. Production-Ready Checklist
- ✅ Use explicit intents — For navigation within your own app.
- ✅ Use implicit intents — For interacting with other apps (share, call, view).
- ✅ Check intent resolve — Always check
resolveActivity()before starting implicit intents. - ✅ Use Activity Result API — For modern activity result handling.
- ✅ Use Parcelable — For passing custom objects (performance over Serializable).
- ✅ Keep intent data small — Avoid passing large data objects.
- ✅ Use default values — When retrieving extras, always provide fallback values.
- ✅ Handle intent filters properly — Declare intents correctly in
AndroidManifest.xml. - ✅ Test deep links — If using implicit intent filters, test with
adb shell am start. - ✅ Use Constants — Define intent keys in a companion object for consistency.
8. Quick Reference — Intent Extras
| Data Type | Put Method | Get Method |
|---|---|---|
String | putExtra(key, value) | getStringExtra(key) |
Int | putExtra(key, value) | getIntExtra(key, default) |
Boolean | putExtra(key, value) | getBooleanExtra(key, default) |
Float | putExtra(key, value) | getFloatExtra(key, default) |
Double | putExtra(key, value) | getDoubleExtra(key, default) |
Long | putExtra(key, value) | getLongExtra(key, default) |
Serializable | putExtra(key, value) | getSerializableExtra(key) |
Parcelable | putExtra(key, value) | getParcelableExtra(key) |
String Array | putExtra(key, value) | getStringArrayExtra(key) |
Int Array | putExtra(key, value) | getIntArrayExtra(key) |
Ready to master Android Development?
Build real-world Android apps with hands-on projects, mentor-led sessions, and placement support.
.png)