I was going through the ActivityResultAPIs introduced in AndroidX and found them very useful so I decided to share my knowledge here.
Use case: The use case is pretty simple, Start a new activity and get some result back from the newly started activity. I know what you are thinking….. startActivityForResult() and onActivityResult() right. You are absolutely right that we have been using these methods for this use case.
Android has introduced ActivityResultAPIs to handle the same use case in a better and easy way plus you get a lot of other features, will discuss these features later :).
Why should one use it: Many of us will have this question that why should we use this API when we already have startActivityForResult(), yes? Let me give you one use case where you may find this API extremely useful.
“When starting an activity for a result, it is possible (and, in cases of memory-intensive operations such as camera usage, almost certain) that your process and your activity will be destroyed due to low memory.”
For this reason, the Activity Result APIs decouples the result callback from the place in your code where you launch the other activity. Since the result callback needs to be available when your process and activity are recreated, the callback must be unconditionally registered every time your activity is created, even if the logic of launching the other activity only happens based on user input or other business logic. (You will see this in the code)” source: developer.android.com
Solution: Let’s discuss the solution to the above-mentioned problem where our process may get killed and we may lose the result.
Let’s discuss each component that we have used in the above code. There are mainly three components while using ActivityResultAPI. Contract, ActivityResultLauncher, ResultCallback.
A Contract defines
An intent which will be used to start an activity and
Receives the result intent from the started activity and parses it.
An activity can be called with an input of type I and produce an output of type O.
In the above example ActivityResultContracts.TakePicture() is a pre built contract provided by Android.
2. ActivityResultLauncher: A launcher that is used to start the process of executing an ActivityResultContract. capturePhoto is nothing but our ActivityResultLauncher which is returned by registerForActivityResult(). In simple words, if we have to start an activity for result using ActivityResultAPI then we will simply use ActivityResultLauncher like capturePhoto.invoke(). This will launch ActivityResultContract which in turn launch the intent to startTheActivity by itself.
3. registerForActivityResult: is used to register a contract and this is the place where you get the callback for the result, in the above example callback is passed as lambda. This method returns an object of ActivityResultLauncher.
TakePicture() Contract that we used in the earlier example was a pre-built contract which has a predefined Intent with it. We use Custom Contract to start an activity for result from one activity or fragment to another. Yes, you heard it right. We can use this API for fragments also. Noticed fragment-ktx:1.3.0-alpha04?
To define a custom contract we need to create
- A class that extends ActivityResultContract class. This is how we decouple the startActivity() and onActivityResult code from the main activity. Let’s look at the code.
2. Register for activity result.
3. Use the launcher returned by registerForActivityResult which is fetchDataFromSecondActivity. Let’s say we want to launch the second activity on click of a button.
“Test Input” is the input that will be passed to createIntent() of the SecondActivityContract.
As usual in the SecondActivity all we have to do is setResult(Activity.RESULT_OK, intent)
That was all about the Custom Contract.
Android provides some really useful Contracts which are pre-built by Android itself. To use these contracts you can use ActivityResultContract class.
For e.g. ActivityResultContracts.TakePicture()
All of the pre-build contracts can be found at https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContract
I personally found permission contracts very useful as we do not have to handle boilerplate code to request Android runtime permissions. This is how we can use permission contracts
- Get a launcher to trigger the permission request
2. Trigger the permission request
Start activity for result from fragment
With ActivityResultAPI it is fairly simple and same as did in activity.
You can find an example on fragment using this API in the following GitHub project