HomeAbout MeContact Me

Android image and video picker using ActivityResultContracts in Jetpack Compose

By Emanuele Papa
Published in Android
September 13, 2022
1 min read
Android image and video picker using ActivityResultContracts in Jetpack Compose

Experimenting with Jetpack Compose you might have trouble doing old things in the new cool way.

One of these things is opening a media picker where the user can select an image or a video: imagine the use case of a Social Media app where you want your users to publish their content.

Let’s make it simple for now: you want your users to be able to select an image from their gallery.

Working with Jetpack Compose, you can just do the following:

val pickMediaActivityResultLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.GetContent()
) { uri: Uri? ->
    //use the received Uri
}

Button(onClick = {
    pickMediaActivityResultLauncher.launch("image/*")
}) {
    Text(text = "Pick media content")
}

Now, imagine you want your users to be able to publish a video. You can just change the MIME Type image/* to video/*, and keep the above code as it is. In the picker which will appear, the users can only select a video from their gallery.

Cool, but this is a Social Media app and users want to publish both pictures and videos, and you don’t want to have two different buttons for them to choose what to pick from their gallery. Unfortunately, the method launch() doesn’t accept a List of MIME Types as a parameter.

To solve this inconvenience, you can create a subclass of ActivityResultContracts.GetContent and set the Intent to handle both image/* and video/* MIME types.

class GetMediaActivityResultContract : ActivityResultContracts.GetContent() {

    override fun createIntent(context: Context, input: String): Intent {
        return super.createIntent(context, input).apply {
            // Force only images and videos to be selectable
            putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*", "video/*"))
        }
    }
}

Once you made this new custom ActivityResultContract you can just launch it like in the previous example:

val pickMediaActivityResultLauncher = rememberLauncherForActivityResult(
    contract = GetMediaActivityResultContract()
) { uri: Uri? ->
    //use the received Uri
}

Button(onClick = {
    pickMediaActivityResultLauncher.launch("*/*")
}) {
    Text(text = "Pick media content")
}

Pay attention, you can’t just pass an empty String to pickMediaActivityResultLauncher.launch() otherwise the system will raise an ActivityNotFoundException because it doesn’t know how to handle that Intent.
You can use the wildcard */* MIME Type to launch the Intent and then your users will be forced to choose only between an image or a video because those are the MIME types you specified in GetMediaActivityResultContract.

Bonus: starting from Android 11 (API Level 30) a built-in Photo picker was introduced. I suggest you to check it out and use this picker on devices running on newer APIs handling different Android versions in your code.


Tags

#android#jetpackcompose#activityresult#imagepicker#videopicker
Previous Article
Flutter code generation with Paddinger at droidcon London 2021
Emanuele Papa

Emanuele Papa

Android Developer

Topics

Android
AWS
Development
Info
Linux
Smart Home
Modding
Windows

Related Posts

Clear all Android SharedPreferences
December 29, 2020
1 min

Quick Links

HomeAbout MeContact MeRSS Feed

Social Media