0
0
Android Kotlinmobile~15 mins

Activity results in Android Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - Activity results
What is it?
Activity results in Android let one screen (Activity) send data back to the screen that started it. When you open a new screen to get some input or choice, you often want to know what the user picked or typed. Activity results provide a way to receive that information once the second screen closes. This helps apps flow smoothly between screens with shared information.
Why it matters
Without activity results, apps would struggle to pass data back from one screen to another, making user interactions clunky and disconnected. Imagine filling a form on one screen and not having the previous screen know what you entered. Activity results solve this by creating a clear, reliable way to send data back, improving user experience and app logic.
Where it fits
Before learning activity results, you should understand basic Android Activities and Intents. After mastering activity results, you can explore more advanced communication patterns like ViewModel sharing, fragments communication, or using modern navigation components.
Mental Model
Core Idea
Activity results are a way for one screen to ask another screen for information and get the answer back when that screen closes.
Think of it like...
It's like sending a friend to the store with a shopping list and waiting for them to come back with the items you asked for.
┌─────────────┐       startActivityForResult()       ┌─────────────┐
│  Activity A │ ───────────────────────────────────▶ │  Activity B │
└─────────────┘                                      └─────────────┘
       ▲                                                      │
       │ <------------------- setResult() + data -----------┘
       │
   onActivityResult()
Build-Up - 7 Steps
1
FoundationWhat is an Activity result?
🤔
Concept: Introduce the idea that one screen can start another and get data back when it finishes.
In Android, an Activity is a screen. Sometimes, you open a new screen to get some input. Activity results let the first screen know what happened on the second screen after it closes. This is done by sending data back as a result.
Result
You understand that Activity results are a way to pass data back from one screen to another.
Understanding that screens can communicate back and forth is key to building interactive apps.
2
FoundationBasic flow of Activity results
🤔
Concept: Learn the simple steps: start second screen, second screen sends back data, first screen receives it.
1. Activity A starts Activity B asking for a result. 2. Activity B does its work and prepares data. 3. Activity B finishes and sends data back. 4. Activity A receives the data and uses it.
Result
You see the full cycle of requesting and receiving data between screens.
Knowing the flow helps you plan how screens interact and share information.
3
IntermediateUsing registerForActivityResult API
🤔Before reading on: do you think startActivityForResult is still the recommended way to get results? Commit to your answer.
Concept: Learn the modern, recommended way to handle activity results using a callback-based API.
Android now prefers registerForActivityResult instead of startActivityForResult. You register a launcher with a contract describing the expected result. When you launch the second screen, the callback runs with the result data when it returns.
Result
You can write cleaner, safer code that handles results without overriding methods.
Understanding this new API prevents bugs and aligns with current Android best practices.
4
IntermediatePassing data back with Intent extras
🤔Before reading on: do you think the result data is sent as a simple string or a complex object? Commit to your answer.
Concept: Learn how to package data inside an Intent to send it back as a result.
Activity B puts data into an Intent using extras (key-value pairs). Then it calls setResult(RESULT_OK, intent) before finishing. Activity A reads these extras in the result callback.
Result
You can send simple or complex data back between screens using Intents.
Knowing how to use Intent extras is essential for flexible data passing.
5
IntermediateHandling cancellation and errors
🤔Before reading on: do you think the result callback always receives data? Commit to your answer.
Concept: Learn how to detect if the user canceled or if no data was sent back.
If Activity B finishes without setting a result or sets RESULT_CANCELED, Activity A's callback receives no data or a canceled status. You must check the result code to handle these cases gracefully.
Result
Your app can respond properly when users back out or no data is returned.
Handling cancellation prevents crashes and improves user experience.
6
AdvancedCustom ActivityResultContracts for complex data
🤔Before reading on: do you think you can only send simple data types as results? Commit to your answer.
Concept: Learn how to create your own contracts to send and receive complex or custom data types safely.
You can define a custom ActivityResultContract that knows how to create an Intent from your data and parse it back. This lets you use types like objects or files without manual Intent handling.
Result
You can build reusable, type-safe result handling for complex app needs.
Custom contracts improve code clarity and reduce bugs in data passing.
7
ExpertLifecycle and memory safety in result handling
🤔Before reading on: do you think result callbacks can be called after the Activity is destroyed? Commit to your answer.
Concept: Understand how the new API ties result callbacks to lifecycle to avoid crashes and leaks.
registerForActivityResult ties the callback to the Activity or Fragment lifecycle. This means callbacks won't be called if the screen is destroyed, preventing crashes. Older methods risk calling code on dead screens.
Result
Your app becomes more stable and memory-safe when handling results.
Knowing lifecycle integration helps avoid subtle bugs and app crashes.
Under the Hood
When you start an Activity for a result, Android keeps track of the request code and the calling Activity. The second Activity sets a result Intent and a result code before finishing. The system then delivers this result back to the original Activity's callback or method. The new registerForActivityResult API uses a launcher object that registers a callback tied to the lifecycle, internally managing request codes and dispatching results safely.
Why designed this way?
Originally, startActivityForResult used integer request codes and a single callback method, which was error-prone and hard to manage. The new API was designed to be safer, clearer, and lifecycle-aware, reducing bugs and boilerplate. It also fits better with modern Android architecture components and encourages modular, testable code.
┌───────────────┐       startActivityForResult()       ┌───────────────┐
│  Caller A     │ ───────────────────────────────────▶ │  Callee B     │
│ (registers    │                                      │ (sets result  │
│  launcher)    │                                      │  and finishes)│
└───────────────┘                                      └───────────────┘
       ▲                                                      │
       │ <------------------- result Intent ------------------┘
       │
   callback tied to lifecycle
Myth Busters - 4 Common Misconceptions
Quick: Does startActivityForResult still work perfectly in all new Android versions? Commit yes or no.
Common Belief:startActivityForResult is the best and only way to get results from Activities.
Tap to reveal reality
Reality:startActivityForResult is deprecated and replaced by registerForActivityResult, which is safer and easier to use.
Why it matters:Using the old method can cause lifecycle bugs and harder-to-maintain code.
Quick: Can you send any object directly as a result without extra work? Commit yes or no.
Common Belief:You can send any object as a result Intent extra without special handling.
Tap to reveal reality
Reality:Only certain data types (Parcelable, Serializable, primitives) can be sent; complex objects need custom contracts or serialization.
Why it matters:Trying to send unsupported types causes crashes or data loss.
Quick: If the user cancels the second Activity, do you always get data back? Commit yes or no.
Common Belief:You always get result data back, even if the user cancels or presses back.
Tap to reveal reality
Reality:If the user cancels, the result code is RESULT_CANCELED and no data is sent back.
Why it matters:Not checking for cancellation can cause your app to crash or behave incorrectly.
Quick: Can result callbacks be called after the Activity is destroyed? Commit yes or no.
Common Belief:Result callbacks can be called anytime, even after the Activity is destroyed.
Tap to reveal reality
Reality:With the new API, callbacks are lifecycle-aware and won't be called after destruction.
Why it matters:This prevents crashes and memory leaks common in older approaches.
Expert Zone
1
Custom ActivityResultContracts can encapsulate complex data parsing, making your code reusable and testable across multiple Activities or Fragments.
2
The lifecycle-awareness of registerForActivityResult means you don't need to manually unregister callbacks, reducing memory leaks and crashes.
3
Request codes in the old API could collide if reused improperly; the new API avoids this by managing codes internally.
When NOT to use
Activity results are not suitable for continuous or streaming data between screens. For such cases, use shared ViewModels, LiveData, or event buses. Also, for communication within the same screen or fragment, prefer direct method calls or observers.
Production Patterns
In production apps, developers use registerForActivityResult with custom contracts for file picking, camera capture, or complex form inputs. They handle cancellation gracefully and often combine results with ViewModel state to maintain UI consistency across configuration changes.
Connections
Callback functions
Activity results use callbacks to deliver data asynchronously.
Understanding callbacks in programming helps grasp how Android delivers results after user actions.
Event-driven programming
Activity results follow event-driven patterns where actions trigger responses later.
Knowing event-driven design clarifies why results come via callbacks, not immediate returns.
HTTP request-response cycle
Like a client sends a request and waits for a response, Activity A requests data and waits for Activity B's result.
Seeing Activity results as request-response helps understand asynchronous communication in apps.
Common Pitfalls
#1Not checking the result code before using data.
Wrong approach:override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { val value = data?.getStringExtra("key") // Use value directly without checking resultCode }
Correct approach:override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == RESULT_OK) { val value = data?.getStringExtra("key") // Use value safely } }
Root cause:Assuming data is always present leads to null pointer exceptions or wrong app behavior.
#2Using startActivityForResult in new projects ignoring deprecation.
Wrong approach:startActivityForResult(intent, REQUEST_CODE) override fun onActivityResult(...) { /* handle result */ }
Correct approach:val launcher = registerForActivityResult(StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val data = result.data // handle data } } launcher.launch(intent)
Root cause:Not updating to modern APIs causes harder-to-maintain and error-prone code.
#3Sending unsupported data types directly in Intent extras.
Wrong approach:val intent = Intent() intent.putExtra("object", myCustomObject) // myCustomObject is not Parcelable or Serializable setResult(RESULT_OK, intent)
Correct approach:Make myCustomObject implement Parcelable or Serializable, or use a custom ActivityResultContract to handle it.
Root cause:Misunderstanding Intent extras data types causes runtime crashes.
Key Takeaways
Activity results let one screen get data back from another screen after it closes, enabling smooth user interactions.
The modern registerForActivityResult API is safer and lifecycle-aware, replacing the older startActivityForResult method.
Data is passed back using Intents with extras, but only supported data types can be sent directly.
Always check the result code to handle cancellations or errors gracefully.
Custom contracts and lifecycle integration make result handling robust and maintainable in real-world apps.