Visit Sponsor

Written by 12:25 pm Android

Android Start Activity for Result – Best Practices & Examples

In Android apps, it’s common for one Activity to launch another and receive a result — for example, picking a contact, selecting a photo, or collecting user input. Traditionally this was done using startActivityForResult() and handling the result in onActivityResult(). However, this approach is now deprecated and replaced with the Activity Result APIs which are safer, clearer, and lifecycle-aware.

This guide explains how to start an activity for a result using both the modern Activity Result APIs and the legacy approach for reference.

Why You Should Use the Modern Activity Result APIs

The previous pattern (startActivityForResult() + onActivityResult()) had several drawbacks:

  • Callback method could become cluttered
  • Difficult to manage multiple result requests
  • Lifecycle confusion when configuration changes occur

The Activity Result APIs solve these by:

  • Providing type-safe contracts
  • Making the code easier to read and maintain
  • Integrating with lifecycle components

Modern Approach: Activity Result APIs

AndroidX provides ActivityResultLauncher and ActivityResultContracts to start child activities and receive results.

Step 1 — Register a Result Launcher

private ActivityResultLauncher<Intent> pickResultLauncher;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    pickResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        result -> {
            if (result.getResultCode() == RESULT_OK) {
                Intent data = result.getData();
                if (data != null) {
                    String value = data.getStringExtra("result_key");
                    // Handle result
                    textView.setText("Result: " + value);
                }
            }
        }
    );
}

Step 2 — Launch the Activity for a Result

Intent intent = new Intent(this, SecondActivity.class);
pickResultLauncher.launch(intent);

This replaces the deprecated startActivityForResult() and neatly scopes result handling.

Example: Child Activity Sending a Result

In SecondActivity, prepare the result and finish:

Intent data = new Intent();
data.putExtra("result_key", "UserSelectedValue");
setResult(RESULT_OK, data);
finish();

Once finished, the registered launcher receives the result automatically.

ActivityResultContracts

Android comes with ready-made contracts for many common tasks:

ContractDescription
StartActivityForResultStart any activity and get an Intent result
TakePictureTake a photo and return a URI
GetContentPick a file or media
RequestPermissionRequest a single permission
RequestMultiplePermissionsRequest multiple permissions

Example — picking an image from the gallery:

private ActivityResultLauncher<String> pickImageLauncher =
    registerForActivityResult(
        new ActivityResultContracts.GetContent(),
        uri -> {
            if (uri != null) imageView.setImageURI(uri);
        }
    );

...

// Trigger image picker
pickImageLauncher.launch("image/*");

No Intent building is needed — a much cleaner API surface.

Legacy Approach (Deprecated)

For older codebases still using the old API:

Start Activity

Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent, 1001);

Handle Result

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == 1001 && resultCode == RESULT_OK) {
        String value = data.getStringExtra("result_key");
        textView.setText("Result: " + value);
    }
}

⚠ This approach is now deprecated in API 30+ and discouraged in modern development.

Returning Results From Fragments

With the modern APIs, you register the launcher inside your Fragment:

private ActivityResultLauncher<Intent> fragmentLauncher =
    registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        result -> { ... }
    );

...

fragmentLauncher.launch(intent);

This binds the lifecycle to the Fragment, not the Activity.

Handling Cancellations and Failures

The callback receives both result code and data:

if (result.getResultCode() == Activity.RESULT_CANCELED) {
    // Handle user cancel
}

You can provide fallback behavior or UI messaging based on cancellation.

Best Practices (Senior Engineering Insight)

From extensive Android experience:

✔ Use Activity Result APIs everywhere instead of legacy methods
✔ Always check for null Intent or missing extras
✔ Use typed contracts (e.g., GetContent, TakePicture) when available
✔ Avoid shared global state — keep result handling scoped and isolated
✔ For complex results, consider a shared ViewModel in multi-Fragment flows

These practices reduce bugs and align with modern Android architecture.

Common Pitfalls and Fixes

Result never arrives:
✔ Ensure you registered the launcher before calling launch().

App crashes on missing extras:
✔ Always perform null checks and default values.

Multiple result requests collide:
✔ Use distinct launchers for separate request flows.

Summary

Starting an activity for a result is a foundational interaction pattern in Android. The modern Activity Result APIs provide a clean, lifecycle-aware mechanism to start child activities, receive results, and handle those results in typed callbacks. This replaces the older startActivityForResult() pattern with a more robust and maintainable solution.

Visited 5 times, 1 visit(s) today
Close