Image Picker on Android. What suits your needs?

Andrei Riik
MobilePeople
Published in
5 min readMay 10, 2023
Photo by Soragrit Wongsa on Unsplash

Let’s imagine a typical case in Android/Kotlin development when you need to make the functionality of sending an image to a back-end. It could be a user’s profile image or an image that the user wants to send into a chat or something else. So how can we implement it?

Obviously, we have the Photo Picker from Google, right? It works, everything is good, end of the story.

Well, not really. Let’s elaborate on the use case a bit.

1. Do we need a choice between a gallery and a camera?

If you need a camera then Photo Picker from Google can’t help you. And here we have at least 2 options:

  • Implement an in-app camera with CameraX or similar libraries. In this way, you’ll partially duplicate the capability of the system camera in your app.
  • Ask the system to take a photo. In this case, you just use the system camera and it provides you the result.

Let’s focus on the second option for now. It’s easy to implement and it doesn’t even require you to declare the android.permission.CAMERA permission in your AndroidManifest (But if you declare it then you need to ask a runtime permission).

Basically, there are 3 steps to implement it:

So it’s quite simple solution if you don’t need to include the real-time camera preview into your app.

Note: The documentation in this link is marked as deprecated but it looks more like a mistake in the documentation. Because the idea of deprecation is related to Camera-1 approach which now is suggested to replace with CameraX. But MediaStore.ACTION_IMAGE_CAPTURE is a different approach and works well.

2. Do we need to have the possibility to crop or rotate the image before sending it?

Obviously not every image from the gallery or especially the camera is ideal. Users may want to edit the image before providing it to your app.

Sounds complicated? Don’t worry, we can use the power of Android community. My personal choice for now is uCrop library. It provides basic editing options, for example: crop, rotate, and limit the output size.

And it has pretty friendly syntax, like this:

UCrop.of(sourceUri, destinationUri)
.withAspectRatio(16, 9)
.withMaxResultSize(maxWidth, maxHeight)
.start(context)

3. What are the limitations of Photo Picker from Google?

Basically, it works via Google Play services but if this functionality isn’t available on some devices then ACTION_OPEN_DOCUMENT will be used instead.

Let’s look at the code.

The typical usage of Photo Picker from Google:

val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->
// Process result from Uri
}

pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

The typical usage of ACTION_OPEN_DOCUMENT for image selection:

val launcher = activity.registerForActivityResult(StartActivityForResult()) {
val uri = it.data?.data
// Process result from Uri
}

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "image/*"
addCategory(Intent.CATEGORY_OPENABLE)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}

launcher.launch(intent)

So if the approach with ACTION_OPEN_DOCUMENT is not much more difficult then what is the value of Photo Picker from Google? Well, it provides some UI and handles the interactions with the file system. It allows us to not declare storage permissions. On the other hand, the approach with ACTION_OPEN_DOCUMENT has the same features and a bit more.

Can Photo Picker from Google get a picture from Google Drive or OneDrive? It’s not mentioned in the documentation and as I tested — No.

Can ACTION_OPEN_DOCUMENT get a picture from such cloud providers? Yes.

The idea of ACTION_OPEN_DOCUMENT is wider than your local file system. The file system is just one of many possible providers here.

In other words, Photo Picker from Google provides a new UI and a few lines shorter integration. But it doesn’t have the ability to get a content from a cloud provider (at least in May 2023). Not good, not bad.

I just want to get a photo from a gallery or camera, do I really need to keep in mind all of this?

Thanks to the power of Android community again, there are some ready-to-use libraries. But some of them are abandoned so eventually I made my own library to handle my needs. It’s based on ACTION_OPEN_DOCUMENT for Gallery source and ACTION_IMAGE_CAPTURE for the Camera source.

Main functionality:

  • Pick a picture from the gallery without storage permission
  • Take a photo from the camera (camera permission is optional)
  • Rotate or crop the captured image
  • Save the final image to app’s local directory so you can use it like a File, without a ContentResolver
  • Transform the result to Jpeg / PNG / WebP automatically if needed

An example of usage:

val launcher = registerForActivityResult(StartActivityForResult()) {
it?.data?.data?.let { uri ->
// Done. Use the received uri with captured image inside.
imageView.setImageURI(uri)
}
}

ImagePickerPlus
.createIntent(
activity = this,
PickRequest(
source = PickSource.GALLERY, // or PickSource.CAMERA
transformation = ImageTransformation(
maxSidePx = 1024, // Or -1 if limit isn't needed
encodeToFormat = ImageFormat.JPEG, // Or null is transformation isn't needed
),
)
)
.let { launcher.launch(it) }

Check it out and leave feedback:

Advanced mode. Your self-made solution

If nothing suits you and you decide to write everything by yourself then let me share some pitfalls that you have to be aware of:

  • Images can be large. Sometimes you can’t just pass a bitmap as is without risk of OutOfMemoryError. It’s a good idea to use proper methods of resizing like it’s described in the documentation.
  • Images can be passed to you in a rotated state. So you have to detect the rotation using ExifInterface.
  • There are many possible images format. But probably you want to focus only on main like Jpeg, PNG, WebP.
  • When you receive an Uri as a result of an image picker, it may not always be an ordinary File. Sometimes it has a content:// scheme and you have to handle it via ContentResolver. In fact, it’s more reliable to handle all Uri via ContentResolver.

Conclusion

There is more than one way to implement the photo picker functionality in your app.

  • If you need a modern UI for the latest Androids and cloud providers are not needed then Photo Picker from Google is OK.
  • Need to have cloud providers? Don’t want to depend on Play Services? Consider using ACTION_OPEN_DOCUMENT with mime filters.
  • Something even more complicated like post-processing and the ability to use a camera along with a gallery? Try to find a library that suits your needs or write this functionality by yourself.

Thanks for reading!

--

--