The ActivityResultRegistry is the recommended approach
ComponentActivity
now provides an ActivityResultRegistry
that lets you handle the startActivityForResult()
+onActivityResult()
as well as requestPermissions()
+onRequestPermissionsResult()
flows without overriding methods in your Activity
or Fragment
, brings increased type safety via ActivityResultContract
, and provides hooks for testing these flows.
It is strongly recommended to use the Activity Result APIs introduced in Android 10 Activity 1.2.0-alpha02 and Fragment 1.3.0-alpha02.
Add this to your build.gradle
def activity_version = "1.2.0-beta01"
// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"
How to use the pre-built contract
This new API has the following pre-built functionalities
- TakeVideo
- PickContact
- GetContent
- GetContents
- OpenDocument
- OpenDocuments
- OpenDocumentTree
- CreateDocument
- Dial
- TakePicture
- RequestPermission
- RequestPermissions
An example that uses the takePicture contract:
private val takePicture = prepareCall(ActivityResultContracts.TakePicture()) { bitmap: Bitmap? ->
// Do something with the Bitmap, if present
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { takePicture() }
}
So what’s going on here? Let’s break it down slightly. takePicture
is just a callback which returns a nullable Bitmap - whether or not it’s null depends on whether or not the onActivityResult
process was successful. prepareCall
then registers this call into a new feature on ComponentActivity
called the ActivityResultRegistry
- we’ll come back to this later. ActivityResultContracts.TakePicture()
is one of the built-in helpers which Google have created for us, and finally invoking takePicture
actually triggers the Intent in the same way that you would previously with Activity.startActivityForResult(intent, REQUEST_CODE)
.
How to write a custom contract
A simple contract that takes an Int as an input and returns a string that the requested Activity returns in the result Intent.
class MyContract : ActivityResultContract<Int, String>() {
companion object {
const val ACTION = "com.myapp.action.MY_ACTION"
const val INPUT_INT = "input_int"
const val OUTPUT_STRING = "output_string"
}
override fun createIntent(input: Int): Intent {
return Intent(ACTION)
.apply { putExtra(INPUT_INT, input) }
}
override fun parseResult(resultCode: Int, intent: Intent?): String? {
return when (resultCode) {
Activity.RESULT_OK -> intent?.getStringExtra(OUTPUT_STRING)
else -> null
}
}
}
class MyActivity : AppCompatActivity() {
private val myActionCall = prepareCall(MyContract()) { result ->
Log.i("MyActivity", "Obtained result: $result")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
button.setOnClickListener {
myActionCall(500)
}
}
}
Check this official documentation for more information.