HomeAbout MeContact Me
Android image and video picker using ActivityResultContracts in Jetpack Compose
Android
Android image and video picker using ActivityResultContracts in Jetpack Compose
Emanuele Papa
Emanuele Papa
September 13, 2022
1 min

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

Previous Article
Flutter code generation with Paddinger at droidcon London 2021
Emanuele Papa

Emanuele Papa

Android Developer

Related Posts

Solve ADB stuck on waiting for debugger
Solve ADB stuck on waiting for debugger
November 06, 2022
1 min

Quick Links

HomeAbout MeContact MeRSS Feed

Social Media