Deep Dive into Activity Results API — No More onActivityResult()
ActivityResultContracts by Examples
Since Android came into existence in 2007,
Activity has been one of its core components. One of the most common tasks in apps is transferring data between two Activities. Until now,
onActivityResult were the only choice.
Through the combination of these two parts, developers are able to transfer data from one
Activity to another and get data back easily.
Let’s elaborate through an example: your app wants to capture an image and display it to the user. You either write your own custom Camera or delegate the task of fetching an image to Android through
Intents. In this second scenario, Android system will open the user-preferred Camera app, capture the image and deliver the requested data to your activity by calling
I am working on the video tutorial of this article and will upload it on my YouTube channel soon. Please subscribe to watch that and more Android tutorials like this.
Traditional Way — The onActivityResult() Method
Whether its an image
Bitmap from Camera app or its a Image from the gallery, or maybe its some custom result from your some other Activity of app, Android system will call
onActivityResult() method in the original requesting
If you one case of capturing image or multiple cases like picking images from gallery, requesting gazillion permissions, and handling your own custom data with app’s other screens, all the results of these actions are handled in only one method
onActivityResult() . And this method will look something like this in your code.
I have a feeling that you don’t like this kind of code to read / write at all. Neither do I. Because this kind of code brings lots of problems and unwanted bugs such as:
Tight Coupling: There’s no other place where you can put or abstract this code and business logic. Like if you want to separate each case of Image Capture or Pick Image etc. You can’t do that. You can delegate later, but starting point is this. And this will create a bad cluster like above code with nested if-else blocks.
Type-Safety: You may get wrong type of data by minor mistakes. You can get your Integer value as String and later spend hours on debugging why app’s not working the way its supposed to. This is because you are relying on String keys to put/read from Intent data. You will have to make sure that you are using right type for the right key.
Unwanted NullPointerException: Who is not annoyed of
NullPointerException? If you get a typo in writing key of to either put or retrieve data in the
Intent, you will get the
NullPointerExceptionlike a bombing crash in your app. This can waste a lot of time as you might debug on why your data is null. How are you supposed to think that you can mistakenly miss some letter in your key at that time?
So, Google brings us a solution which is cleaner in code readability with not much if-else blocks, less coupling and separate places for each case, type safety to make sure the right data gets to right method, and absolutely no
NullPointerException because of typos.
Introducing Activity Results API — The New Way
I’m not sure what this will be called — Activity Results API or Activity Result Contracts or both. But surely it sounds nice.
Activity 1.2.0-alpha02 and
Fragment 1.3.0-alpha02, you now have a nice abstraction which allows you to handle
onActivityResult() method in a very clean and reusable structure.
Let’s see how this new API is used then.
First, you have to add the following dependencies in your app’s
Please note that at the time of writing this article, latest version is
fragment-ktx . You can check the latest version from the Google Maven link. These APIs are in the alpha stage yet, so API is not final yet. These can be changed at any time. The article works with
alpha04 version but may or may not work with earlier or later versions.
The Process for Activity Results API
The process to use this new API looks like this.
1. Create Contract
First, you have to either define your contract or use any existing one. A contract is the implementation of
ActivityResultContract interface. Taken from the documentation, this is a contract specifying that an activity can be called with an input of type I and produce an output of type O.
Here’s a an example of
SimpleContract which takes an Integer as input and returns some String data from the child Activity.
createIntent() method is used to create the valid
Intent which will be passed in
startActivityForResult() method once this contract is called. And the
parseResult() method will behave as a proxy for
onActivityResult() method and is parsing the result
Intent and extracting the data from it.
You can see that we don’t need to put bunch of if-else blocks in
onActivityResult() method anymore. Because each case will be handled like this in separate implementation and separate
parseResult() method. This is the beauty and simplicity of the Activity Results API.
2. Register Contract
The next step is to register this
SimpleContract with the Activity Results API. This is done through calling
Please note that in previous versions
alpha03, this method was called as
prepareCall(). But in
alpha04, this was renamed to
You can see how easy it to register your contract. And with the simplicity of beloved Kotlin, you will get the result in a nice lambda method. This will be called after the
parseResult() method from the contract and will give you the result (in our case a nullable String). You can check for the NULL value to see if user cancelled the action or the result was
RESULT_OK from the child activity.
3. Call Contract
Finally, all you have to do is make the call to this new registration variable which is
simpleContractRegistration in the above snippet. Go ahead and call it just like any ordinary method. And all the input you defined in the contract will be passed as type-safe parameters in your method call.
And voila. No more
onActivityResult() now. You can easily use this with your own custom
Fragmentclasses and it will be very clean, organized, and reusable code with type-safe parameters.
Now that you have seen how simple it is to use the Activity Result API and create your own contracts. You will be super glad to know that Google has provided some very useful pre-built contracts. These can be accessed statically from the
ActivityResultContracts class. Let’s explore some examples below.
Capturing Images — ActivityResultContracts.TakePicture()
You can easily capture the images from Camera without any hassle of Media Intent.
Pick Images — ActivityResultContracts.GetContent
This allows you to pick not only images but you can also select other files from your device. You have to provide mimeType of the files you need in app.
Requesting Permissions — ActivityResultContracts.RequestPermission
Now this is my most favorite one. I remember that I had to write like 100 lines of code to ask for multiple permissions to handle a very complex flow. I had written about it details in this article when there were no Activity Results API yet.
The Activity Results API provides two methods —
RequestMultiplePermissions . These two does exactly what their names are. Here’s a quick example code.
I have created a simple demo project with some example contracts as discussed in this article on the following Github repository. You can explore more and play with it.
Wrapping it up now, in this article we discussed about some problems in the traditional
onActivityResult() way. And then we got to learn about new Activity Results API. Then we created an example contract to see how different parts work together. And finally we saw some pre-built contracts like image capturing, picking images, permission handling etc.
At the end, please don’t forget to Subscribe to my newsletter to get more tutorials and tips on Android development directly in your inbox.
Thanks to Roberto Orgiu for reviewing and providing feedback on this post 🙌