Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
📱 Device Features  ·  Lesson 36

Camera & Gallery (Pick Image)

Two ways to get a photo

Photo Picker

  • User chooses an existing image
  • No permission needed
  • PickVisualMedia()

Camera

  • User takes a new photo
  • Camera app saves it to your file
  • TakePicture() + FileProvider
Both use the Activity Result API
9:41▮▮ 85%←New Note⋮Title: Chemistry lab🖼️photo of the experiment🖼 Add photoRemoveSAVE NOTE9:41▮▮ 85%Add photo⋮Maths homeworkHighAdd photoChoose a sourceGALLERYCAMERA
Attaching a photo to a note

Photo Picker (gallery)

Kotlin
// From Student Diary – AddEditNoteFragment
private val pickImage = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri: Uri? ->
    if (uri != null) copyImage(uri)          // null = user cancelled
}

binding.btnAddPhoto.setOnClickListener {
    pickImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}

// pick up to 5 images
private val pickMany = registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
    adapter.submitList(uris)
}

Keep the photo: copy to app storage

Kotlin – util/ImageStore.kt
package com.codingeasily.studentdiary.util

import android.content.Context
import android.net.Uri
import java.io.File
import java.util.UUID

/**
 * The photo picker gives a temporary content:// Uri.
 * We copy the picture into the app's private folder so it stays available.
 */
object ImageStore {
    fun copyToAppStorage(context: Context, uri: Uri): String? = try {
        val dir = File(context.filesDir, "images").apply { mkdirs() }
        val file = File(dir, "${UUID.randomUUID()}.jpg")
        context.contentResolver.openInputStream(uri)?.use { input ->
            file.outputStream().use { output -> input.copyTo(output) }
        }
        file.absolutePath
    } catch (e: Exception) {
        null
    }

    fun delete(path: String?) {
        if (path != null) File(path).delete()
    }
}
Kotlin – using it
private fun copyImage(uri: Uri) {
    viewLifecycleOwner.lifecycleScope.launch {
        val path = withContext(Dispatchers.IO) { ImageStore.copyToAppStorage(requireContext(), uri) }
        if (path == null) {
            Toast.makeText(requireContext(), R.string.image_error, Toast.LENGTH_SHORT).show()
        } else {
            imagePath = path                                   // saved with the note in Room
            Glide.with(this@AddEditNoteFragment).load(File(path)).centerCrop().into(binding.ivPhoto)
        }
    }
}
Pickercontent:// UriIO threadcopy bytesfilesDir/images/uuid.jpgpermanentRoomimagePath column
Store a path, not the image bytes, in the database

Take a photo with the camera

Kotlin
class ProfileFragment : Fragment() {
    private var photoUri: Uri? = null

    private val takePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
        if (success) photoUri?.let { Glide.with(this).load(it).circleCrop().into(binding.ivAvatar) }
    }

    private fun openCamera() {
        val file = File(requireContext().filesDir, "images/avatar_${System.currentTimeMillis()}.jpg")
        file.parentFile?.mkdirs()
        val uri = FileProvider.getUriForFile(
            requireContext(), "${requireContext().packageName}.fileprovider", file
        )
        photoUri = uri
        takePicture.launch(uri)              // the camera app writes the photo into our file
    }
}

FileProvider setup

Other apps (the camera) cannot write to your private folder directly. A FileProvider creates a safe content:// Uri for one file.

XML
<!-- AndroidManifest.xml – inside <application> -->
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

<!-- res/xml/file_paths.xml -->
<paths>
    <files-path name="images" path="images/" />
</paths>

Let the user choose: camera or gallery

Kotlin
private fun choosePhotoSource() {
    val options = arrayOf("📷  Take photo", "🖼  Choose from gallery")
    MaterialAlertDialogBuilder(requireContext())
        .setTitle("Add photo")
        .setItems(options) { _, which ->
            if (which == 0) openCamera()
            else pickImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
        }
        .show()
}

Common mistakes

  • Requesting READ_EXTERNAL_STORAGE / READ_MEDIA_IMAGES just to pick a photo → not needed with Photo Picker (and Play may reject the app).
  • Passing Uri.fromFile(file) to the camera → FileUriExposedException; use FileProvider.
  • Authority in code not matching the manifest → "Failed to find configured root".
  • Saving full-size photos in Room as bytes → huge database; store the file path.

Summary

  • Gallery: PickVisualMedia (no permission); copy the result into filesDir.
  • Camera: TakePicture + a FileProvider Uri.
  • Show with Glide; store only the path.
✅ Practice

Add a profile screen with a round avatar. Tapping it offers "Take photo" or "Choose from gallery"; the chosen image is saved and still visible after restarting the app.

Frequently Asked Questions

Does the Photo Picker work on old Android versions?
Yes. On devices without the system picker, AndroidX falls back to the document picker (ACTION_OPEN_DOCUMENT), so the same code works on Android 5+.
Do I need CAMERA permission for TakePicture?
No, the camera app takes the photo. But if your manifest declares the CAMERA permission for another feature, you must request it before launching TakePicture.
Why copy the picked image?
The Uri from the picker may stop working after the app restarts. Copying the file into filesDir gives you a permanent path you can store in Room.
← Android Tutorial (Kotlin)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicNotifications & Channels Your progress: 36 / 43 (84%) · Lesson 37 / 43 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free