📱 Device Features · Lesson 36
Camera और Gallery (Image चुनें)
Photo पाने के दो तरीके
Photo Picker
- User मौजूदा image चुनता है
- कोई permission नहीं
- PickVisualMedia()
Camera
- User नई photo लेता है
- Camera app आपकी file में save करती है
- TakePicture() + FileProvider
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)
}Photo रखें: app storage में copy
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 – use करना
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)
}
}
}Camera से photo लें
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
दूसरी apps (camera) आपके private folder में सीधे नहीं लिख सकतीं। FileProvider एक file के लिए safe content:// Uri बनाता है।
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>User चुने: camera या 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()
}आम गलतियाँ
- सिर्फ़ photo चुनने के लिए READ_EXTERNAL_STORAGE / READ_MEDIA_IMAGES माँगना → Photo Picker के साथ ज़रूरत नहीं (और Play app reject कर सकता है)।
- Camera को
Uri.fromFile(file)देना →FileUriExposedException; FileProvider use करें। - Code की authority manifest से मेल न खाए → "Failed to find configured root"।
- Full-size photos Room में bytes के रूप में → बहुत बड़ा database; file path store करें।
सारांश
- Gallery:
PickVisualMedia(permission नहीं); result कोfilesDirमें copy करें। - Camera:
TakePicture+ FileProvider Uri। - Glide से दिखाएँ; सिर्फ़ path store करें।
✅ Practice
गोल avatar वाली profile screen जोड़िए। उस पर tap करने से "Take photo" या "Choose from gallery" मिले; चुनी image save हो और app restart के बाद भी दिखे।
अक्सर पूछे जाने वाले प्रश्न (FAQ)
क्या Photo Picker पुराने Android versions पर चलता है?
हाँ। जिन devices पर system picker नहीं है वहाँ AndroidX document picker (ACTION_OPEN_DOCUMENT) पर चला जाता है, इसलिए वही code Android 5+ पर चलता है।
TakePicture के लिए CAMERA permission चाहिए?
नहीं, photo camera app लेती है। पर अगर manifest में किसी और feature के लिए CAMERA permission declare है तो TakePicture launch करने से पहले उसे request करना पड़ेगा।
चुनी हुई image copy क्यों करें?
Picker का Uri app restart के बाद काम करना बंद कर सकता है। File को filesDir में copy करने से permanent path मिलता है जिसे Room में store कर सकते हैं।
