Activities & Intents (Java)
An Activity is a single, focused screen in your app. An Intent is a message object you use to start activities, services, or deliver broadcasts. Together, they drive navigation, data handoff, and interactions with other apps.
Big Picture
Activity
UI screen with lifecycle & state
Intent
“What to do” + optional data
Resolver
Finds matching component
Target
New screen / external app
Explicit vs Implicit Intents
| Type | Use Case | How it Resolves | Example |
|---|---|---|---|
| Explicit | Navigate inside your app | You specify the exact class | new Intent(this, DetailActivity.class) |
| Implicit | Ask system/other apps to handle an action | Intent resolver matches action/data to registered intent-filters | ACTION_SEND with text/plain to share text |
// Explicit: open DetailActivity
Intent intent = new Intent(CurrentActivity.this, DetailActivity.class);
intent.putExtra("ITEM_ID", 42);
startActivity(intent);
// Implicit: share text
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("text/plain");
share.putExtra(Intent.EXTRA_TEXT, "Hello from CodingwithSonu!");
startActivity(Intent.createChooser(share, "Share via"));
Passing Data (Extras & Bundles)
Attach key-value pairs with putExtra (or a Bundle) and read them in the target activity.
// Sender
Intent i = new Intent(this, ProfileActivity.class);
i.putExtra("name", "Sonu");
i.putExtra("age", 28);
ArrayList<String> hobbies = new ArrayList<>();
hobbies.add("Android"); hobbies.add("Biking");
i.putStringArrayListExtra("hobbies", hobbies);
startActivity(i);
// Receiver (ProfileActivity)
String name = getIntent().getStringExtra("name");
int age = getIntent().getIntExtra("age", 0);
ArrayList<String> h = getIntent().getStringArrayListExtra("hobbies");
Activity Result API (Modern way)
Instead of the old startActivityForResult(), use the Activity Result API to get results safely across configuration changes.
// In Activity (Java): register a launcher at field scope
private ActivityResultLauncher<Intent> pickContactLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
// TODO: read selected contact from data
}
});
// Launch somewhere
Intent pick = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
pickContactLauncher.launch(pick);
Intent-Filters (Manifest)
Components advertise what they can handle. The resolver compares an implicit intent’s action/data/category to these.
<!-- In AndroidManifest.xml -->
<activity android:name=".ShareActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
Tasks & Back Stack (Essentials)
Each Activity belongs to a task (a stack). Pressing back pops the top Activity. Launch modes and flags control stack behavior.
| Flag / Mode | Effect | Common Use |
|---|---|---|
| FLAG_ACTIVITY_CLEAR_TOP | Clear above target if it exists | Return to existing instance |
| FLAG_ACTIVITY_NEW_TASK | Start in a new task | Launch from notification/service |
| singleTop (manifest) | Reuse if already at top | Home screens, detail screens |
| singleTask (manifest) | One instance per task | Main entry points |
PendingIntent (for Notifications/Alarms)
A PendingIntent wraps an intent so other processes (e.g., NotificationManager, AlarmManager) can execute it on your behalf with your app’s identity.
// Create an explicit Intent for an Activity
Intent open = new Intent(this, DetailActivity.class);
open.putExtra("from", "notification");
PendingIntent contentPI = PendingIntent.getActivity(
this, 1001, open,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
Common Patterns
1) Open details with an ID
Intent i = new Intent(this, ProductDetailActivity.class);
i.putExtra("PRODUCT_ID", productId);
startActivity(i);
2) Share an image (file provider)
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", imageFile);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
share.putExtra(Intent.EXTRA_STREAM, uri);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(share, "Share image"));
3) Open map direction (implicit VIEW)
Uri gmmIntentUri = Uri.parse("geo:0,0?q=India Gate, New Delhi");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
Error Handling & Safety
- Intent may not resolve: Check with resolveActivity(getPackageManager()) before startActivity().
- Large data in extras: Avoid huge bitmaps/arrays; use file URIs or a shared repository (DB).
- Security: Be careful with exported=true. Only expose what’s necessary.
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://codingwithsonu.com"));
if (i.resolveActivity(getPackageManager()) != null) {
startActivity(i);
} else {
Toast.makeText(this, "No app can handle this action", Toast.LENGTH_SHORT).show();
}
Hands-On Exercise
- Create SecondActivity that displays a greeting from MainActivity.
- Add a button in MainActivity to open SecondActivity with name as extra.
- Use the Activity Result API to let SecondActivity return a resultMessage back.
// In MainActivity
private ActivityResultLauncher<Intent> launcher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), res -> {
if (res.getResultCode() == RESULT_OK && res.getData() != null) {
String msg = res.getData().getStringExtra("resultMessage");
Toast.makeText(this, "From SecondActivity: " + msg, Toast.LENGTH_SHORT).show();
}
});
public void openSecond(View v) {
Intent i = new Intent(this, SecondActivity.class);
i.putExtra("name", "Sonu");
launcher.launch(i);
}
// In SecondActivity
String name = getIntent().getStringExtra("name");
TextView tv = findViewById(R.id.tvHello);
tv.setText("Hello, " + name + "!");
public void finishWithResult(View v) {
Intent data = new Intent();
data.putExtra("resultMessage", "Nice to meet you.");
setResult(RESULT_OK, data);
finish();
}
Troubleshooting
“Activity class does not exist” ➜ Check package name & manifest registration.
No app handles implicit intent ➜ Guard with resolveActivity() and/or use createChooser().
Data lost on rotation ➜ Use onSaveInstanceState, ViewModel, or persistent storage.
App crashes on File URI ➜ Use FileProvider and grant URI permission.
Best Practices
- Keep Activities thin; move logic to ViewModels/helpers.
- Prefer explicit intents for in-app navigation.
- Validate external intents; never trust incoming data blindly.
- Use Activity Result API (avoid legacy request codes).
- Minimize exported components; least-privilege principle.