1. Overview
In this article, we will learn about the alternative for the startActivityForResult deprecated camera.
Android introduced the Activity Result APIs as a major change in the androidx.activity:activity:1.2.0
and androidx.activity:activity-ktx:1.2.0
releases.
This API improves code readability, avoids writing code for requesting camera permissions, improves type safety.
2. Old way using startActivityForResult camera
In the old way, we perform the following to get the required result from the Camera application:
- Get permission CAMERA and WRITE_EXTERNAL_STORAGE
- Create an Intent
- Pass intent and also request code to
startActivityForResult
method. The request code returned in theonActivityResult
to identify the request (Intent) for which the result came back. - Register onActivityResult to retrieve the result
For example, the following code requests the CAMERA and WRITE_EXTERNAL_STORAGE permissions to capture video or picture.
private void activeTakePhoto() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 110); } else { takePicture(); } } public void takePicture() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, REQUEST_IMAGE_CAPTURE); }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == 110) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) { takePicture(); } }}
The following code retrieves the result Bitmap.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK){ Bundle extra = data.getExtras(); Bitmap bitmap = (Bitmap) extra.get("data"); imageView.setImageBitmap(bitmap) ; } }
3. Alternative to deprecated startActivityForResult camera
The Activity Result APIs provide the registerForActivityResult
in place of startActivityForResult +
onActivityResult
.
The registerForActivityResult
method takes the following two parameters and returns ActivityResultLauncher
as output:
1. ActivityResultContracts
A contract defines the type of action or interaction (Intent) requested from an activity. After getting the result from the activity, it then produces the output of a particular type that makes calling activity for result type-safe.
A collection of standard ActivityResultContracts available for use. Among the contracts available, the TakePicture
contract is the replacement to the startActivityForResult
camera Intent.
2. ActivityResultCallback
The callback is to be called once the activity result is available. Whatever code you plan to write in your old onActivityResult
method must be placed here.
private val takePictureLauncher = registerForActivityResult( ActivityResultContracts.TakePicture() ) { isSuccess -> if (isSuccess) { // success } else { // handle failure } }
For example, the below registerForActivityResult
method takes the ActivityResultContracts.TakePicture
as contract and then returns the ActivityResultLauncher
as output.
Once you have the ActivityResultLauncher
, you can launch the activity using the launch
method:
private fun takeImage() { val photoFile: File? = viewModel.createImageFile() photoFile?.also { // You must set up file provider to expose the url to Camera app val photoURI: Uri = FileProvider.getUriForFile( requireContext(), BuildConfig.APPLICATION_ID +".fileProvider", it ) takePictureLauncher.launch(photoURI) } }
You had to pass Uri for getting a full image from the Camera app.
fun createImageFile(): File? { return try { val file = File(storageDir, "fullImage.jpg") if (file.createNewFile() || file.exists()) { file } else { null } } catch (ex: IOException) { ex.printStackTrace() null } }
If you only require a preview of the image, you can use the following code:
cameraActivityLauncher.launch(null) private val cameraActivityLauncher = registerForActivityResult(ActivityResultContracts.TakePicture(){ bitmap -> // we get bitmap as result directly }
Notice that we haven’t passed any request code here as registerForActivityResult
automatically takes care of everything including request permissions.
4. Conclusion
To sum up, we have discussed the Activity Result API available from androidx 1.2.0 releases as an alternative to the deprecated startActivityForResult camera. You can also refer settings panel article where we are using the Activity Result API for launching the settings panel.