Android CameraX nel 2026: Cattura Foto e Video con Domande per Colloqui
Tutorial CameraX per sviluppatori Android: gestione del lifecycle, cattura foto e video con Jetpack Compose e domande tecniche per colloqui.

Android CameraX semplifica lo sviluppo della fotocamera astraendo la complessità hardware dietro un'API lifecycle-aware. Con la versione 1.6.2 ora stabile e la migrazione a CameraPipe completata, CameraX offre lo stesso stack camera ad alte prestazioni che alimenta l'app fotocamera Pixel.
CameraX 1.6 è migrato a CameraPipe, utilizza Media3 Muxer come default per VideoCapture e ha stabilizzato l'API SessionConfig. I builder DSL Kotlin (preview { }, imageCapture { }, videoCapture { }) riducono il boilerplate del 40%.
Architettura CameraX e Modello Use Case
CameraX fornisce quattro use case primari che possono essere eseguiti contemporaneamente: Preview, ImageCapture, ImageAnalysis e VideoCapture. Ogni use case si lega a un LifecycleOwner, così la fotocamera si avvia e si ferma automaticamente con l'activity o il fragment.
Il CameraProvider agisce come factory che istanzia questi use case e li lega alla fotocamera. Questo disaccoppiamento significa che lo stesso codice funziona su dispositivi di diversi OEM senza preoccuparsi delle peculiarità specifiche del produttore.
class CameraSetup(
private val context: Context,
private val lifecycleOwner: LifecycleOwner
) {
private lateinit var cameraProvider: ProcessCameraProvider
private var imageCapture: ImageCapture? = null
private var videoCapture: VideoCapture<Recorder>? = null
suspend fun initialize() {
// ProcessCameraProvider lega gli use case al lifecycle
cameraProvider = ProcessCameraProvider.getInstance(context).await()
}
fun bindUseCases(previewView: PreviewView) {
// Slegare gli use case esistenti prima di rilegarli
cameraProvider.unbindAll()
// Use case Preview mostra il feed della fotocamera
val preview = Preview.Builder()
.build()
.apply { setSurfaceProvider(previewView.surfaceProvider) }
// ImageCapture per le foto
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
// VideoCapture con Recorder
val recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(Quality.FHD))
.build()
videoCapture = VideoCapture.withOutput(recorder)
// Legare tutti gli use case al lifecycle
cameraProvider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
imageCapture,
videoCapture
)
}
}La chiamata bindToLifecycle connette gli use case sia all'hardware della fotocamera che al lifecycle. Quando il LifecycleOwner entra nello stato STARTED, la fotocamera si apre. Quando entra in STOPPED, si chiude automaticamente.
Implementazione della Cattura Foto con ImageCapture
ImageCapture fornisce due modalità di cattura: CAPTURE_MODE_MINIMIZE_LATENCY per una risposta rapida dello scatto e CAPTURE_MODE_MAXIMIZE_QUALITY per scatti ad elaborazione intensiva. La scelta dipende se l'app dà priorità alla velocità (app social) o alla qualità (scanner di documenti).
class PhotoCaptureManager(
private val context: Context,
private val imageCapture: ImageCapture
) {
private val mainExecutor = ContextCompat.getMainExecutor(context)
fun capturePhoto(onResult: (Uri?) -> Unit) {
// Generare nome file univoco con timestamp
val filename = "IMG_${System.currentTimeMillis()}.jpg"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
// Salvare nella cartella Pictures/CameraX su Android 10+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX")
}
}
val outputOptions = ImageCapture.OutputFileOptions.Builder(
context.contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
).build()
imageCapture.takePicture(
outputOptions,
mainExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(results: ImageCapture.OutputFileResults) {
// results.savedUri contiene l'URI MediaStore
onResult(results.savedUri)
}
override fun onError(exception: ImageCaptureException) {
Log.e("PhotoCapture", "Cattura fallita: ${exception.message}")
onResult(null)
}
}
)
}
}CameraX 1.5 ha aggiunto il supporto per la cattura DNG (RAW) per le app che necessitano di dati grezzi dal sensore. Verificare le capacità del dispositivo con ImageCapture.getImageCaptureCapabilities() prima di abilitare l'output RAW.
Registrazione Video con VideoCapture e Recorder
VideoCapture utilizza un oggetto Recorder per gestire encoding e muxing. L'API Recorder segue un pattern prepare-start-stop che gestisce la sincronizzazione audio automaticamente.
class VideoRecordingManager(
private val context: Context,
private val videoCapture: VideoCapture<Recorder>
) {
private var activeRecording: Recording? = null
fun startRecording(onEvent: (VideoRecordEvent) -> Unit): Boolean {
// Verificare se è già in registrazione
if (activeRecording != null) return false
val filename = "VID_${System.currentTimeMillis()}.mp4"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX")
}
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(
context.contentResolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
)
.setContentValues(contentValues)
.build()
// Preparare la registrazione con audio se il permesso è concesso
val pendingRecording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
if (hasAudioPermission()) {
pendingRecording.withAudioEnabled()
}
// Avviare la registrazione e salvare il riferimento
activeRecording = pendingRecording.start(
ContextCompat.getMainExecutor(context)
) { event ->
onEvent(event)
// Cancellare il riferimento quando la registrazione è completata
if (event is VideoRecordEvent.Finalize) {
activeRecording = null
}
}
return true
}
fun stopRecording() {
activeRecording?.stop()
}
fun pauseRecording() {
activeRecording?.pause()
}
fun resumeRecording() {
activeRecording?.resume()
}
private fun hasAudioPermission(): Boolean {
return ContextCompat.checkSelfPermission(
context,
Manifest.permission.RECORD_AUDIO
) == PackageManager.PERMISSION_GRANTED
}
}CameraX 1.5 ha aggiunto il supporto per video slow-motion. Interrogare le capacità con Recorder.getHighSpeedVideoCapabilities() prima di abilitare la registrazione a 120fps o 240fps.
Pronto a superare i tuoi colloqui su Android?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
CameraX con Jetpack Compose
CameraX 1.5 ha introdotto l'artifact camera-compose con un composable CameraXViewfinder. Per le app che utilizzano ancora PreviewView basato su View, AndroidView fornisce l'interoperabilità.
@Composable
fun CameraPreview(
modifier: Modifier = Modifier,
onPreviewViewCreated: (PreviewView) -> Unit
) {
AndroidView(
modifier = modifier.fillMaxSize(),
factory = { context ->
PreviewView(context).apply {
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
scaleType = PreviewView.ScaleType.FILL_CENTER
onPreviewViewCreated(this)
}
}
)
}
@Composable
fun CameraScreen(viewModel: CameraViewModel = viewModel()) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(Unit) {
viewModel.initializeCamera(context, lifecycleOwner)
}
Box(modifier = Modifier.fillMaxSize()) {
CameraPreview(
onPreviewViewCreated = { previewView ->
viewModel.bindPreview(previewView)
}
)
// Overlay pulsanti di cattura
Row(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(32.dp),
horizontalArrangement = Arrangement.spacedBy(24.dp)
) {
IconButton(
onClick = { viewModel.capturePhoto() }
) {
Icon(Icons.Default.Camera, "Scatta foto")
}
IconButton(
onClick = { viewModel.toggleRecording() }
) {
Icon(
if (viewModel.isRecording) Icons.Default.Stop
else Icons.Default.Videocam,
"Registra video"
)
}
}
}
}Per implementazioni Compose-first, la guida alle domande per colloqui Jetpack Compose tratta pattern di integrazione ViewModel che si applicano direttamente alla gestione dello stato della fotocamera.
Gestione dei Permessi della Fotocamera
Android richiede il permesso CAMERA a runtime. RECORD_AUDIO è necessario solo quando si registra video con audio. Il flusso dei permessi dovrebbe spiegare perché l'accesso è necessario prima di richiederlo.
class CameraPermissionHandler(private val activity: ComponentActivity) {
private val requiredPermissions = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
)
private val permissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val cameraGranted = permissions[Manifest.permission.CAMERA] == true
val audioGranted = permissions[Manifest.permission.RECORD_AUDIO] == true
if (cameraGranted) {
onCameraPermissionGranted(audioGranted)
} else {
onCameraPermissionDenied()
}
}
fun checkAndRequestPermissions() {
when {
hasAllPermissions() -> onCameraPermissionGranted(hasAudioPermission())
shouldShowRationale() -> showPermissionRationale()
else -> permissionLauncher.launch(requiredPermissions)
}
}
private fun hasAllPermissions(): Boolean {
return requiredPermissions.all { permission ->
ContextCompat.checkSelfPermission(
activity, permission
) == PackageManager.PERMISSION_GRANTED
}
}
private fun hasAudioPermission(): Boolean {
return ContextCompat.checkSelfPermission(
activity,
Manifest.permission.RECORD_AUDIO
) == PackageManager.PERMISSION_GRANTED
}
private fun shouldShowRationale(): Boolean {
return requiredPermissions.any { permission ->
ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
}
}
}Domande per Colloqui su CameraX
CameraX appare nei colloqui Android quando si discute di integrazione della fotocamera, gestione del lifecycle o astrazione hardware. Queste domande testano la comprensione dell'architettura e i dettagli pratici di implementazione.
Perché usare CameraX invece di Camera2?
CameraX astrae le peculiarità specifiche del dispositivo che Camera2 espone direttamente. Un'implementazione Camera2 richiede la gestione di centinaia di workaround specifici per dispositivo. CameraX incorpora queste correzioni nella libreria, testata contro il CameraX Test Lab che copre oltre 150 modelli di dispositivi.
Il binding lifecycle-aware elimina la gestione manuale delle risorse. Camera2 richiede chiamate esplicite open/close che causano leak se non gestite correttamente in ogni callback del lifecycle.
Come lega CameraProvider gli use case al lifecycle?
CameraProvider utilizza internamente il pattern LifecycleObserver. Quando si chiama bindToLifecycle(), registra un observer sul LifecycleOwner fornito. Questo observer riceve eventi ON_START e ON_STOP per aprire e chiudere la fotocamera.
L'insight chiave: CameraX non avvia la fotocamera immediatamente al bind. Aspetta che il lifecycle raggiunga lo stato STARTED, che corrisponde al timing di Activity.onStart().
Cosa succede quando si legano use case incompatibili?
Non tutte le combinazioni di use case funzionano su tutti i dispositivi. Preview + VideoCapture + ImageAnalysis + ImageCapture potrebbe fallire su hardware più datato. CameraX lancia una IllegalArgumentException al momento del bind, non a runtime.
La soluzione è verificare CameraProvider.hasCamera() e le capacità del dispositivo prima di legare combinazioni complesse. Per app critiche, testare esplicitamente su dispositivi di fascia bassa.
Spiegare la differenza tra CAPTURE_MODE_MINIMIZE_LATENCY e CAPTURE_MODE_MAXIMIZE_QUALITY
MINIMIZE_LATENCY riduce il ritardo dello scatto usando pipeline di elaborazione più veloci, possibilmente saltando qualche post-elaborazione. MAXIMIZE_QUALITY applica l'elaborazione HDR+ completa, riduzione del rumore e cattura multi-frame su dispositivi supportati.
Il compromesso: la modalità latency cattura in 100-200ms, la modalità quality può richiedere 500ms-1s a seconda dell'illuminazione. Le app social tipicamente scelgono latency. Le app scanner documenti scelgono quality.
Come gestisce CameraX la rotazione del dispositivo?
CameraX gestisce la rotazione automaticamente attraverso l'impostazione target rotation. Di default, usa la rotazione del Display, ma le app possono sovrascriverla con setTargetRotation(). I dati EXIF dell'immagine di output contengono il tag di orientamento corretto.
Per PreviewView, lo scaleType gestisce le differenze di aspect ratio. FILL_CENTER ritaglia per riempire, FIT_CENTER mostra il letterboxing. La scelta dipende se l'app dà priorità all'anteprima a schermo intero o all'evitare il ritaglio.
Dipendenze e Setup per CameraX 1.6
La libreria CameraX è divisa in più artifact. Includere solo ciò che l'app utilizza per minimizzare la dimensione dell'APK.
dependencies {
val cameraxVersion = "1.6.2"
// Libreria core richiesta per tutti gli use case
implementation("androidx.camera:camera-core:$cameraxVersion")
// Implementazione Camera2 (richiesta)
implementation("androidx.camera:camera-camera2:$cameraxVersion")
// Integrazione lifecycle
implementation("androidx.camera:camera-lifecycle:$cameraxVersion")
// Use case VideoCapture
implementation("androidx.camera:camera-video:$cameraxVersion")
// PreviewView e componenti UI fotocamera
implementation("androidx.camera:camera-view:$cameraxVersion")
// Opzionale: Extensions (Night mode, HDR, ecc.)
implementation("androidx.camera:camera-extensions:$cameraxVersion")
// Opzionale: Effetti in tempo reale
implementation("androidx.camera:camera-effects:$cameraxVersion")
}
android {
// CameraX richiede bytecode Java 11
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}Il Manifest necessita di dichiarazioni feature e permessi:
<!-- AndroidManifest.xml -->
<manifest>
<!-- Requisito hardware fotocamera -->
<uses-feature android:name="android.hardware.camera.any" />
<!-- Permessi runtime -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>I pattern correlati per Kotlin Coroutines si applicano quando si wrappano le chiamate ListenableFuture di CameraX in funzioni suspend.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Cosa Cambia CameraX 1.6 per le App in Produzione
CameraX 1.6 ha portato tre cambiamenti che influenzano le implementazioni esistenti:
-
Backend CameraPipe: Lo stack camera interno ora usa CameraPipe, la stessa architettura della fotocamera Pixel. Questo migliora le prestazioni sui dispositivi Pixel e fornisce una base più pulita per funzionalità avanzate. Il codice esistente non necessita di modifiche.
-
Media3 Muxer default: VideoCapture ora usa Media3 Muxer invece di MediaMuxer. Questo migliora la resilienza ai crash: se l'app termina durante la registrazione, il file video rimane riproducibile. La superficie API è invariata.
-
API SessionConfig stabile: Le app possono ora configurare impostazioni avanzate della fotocamera attraverso SessionConfig senza annotazioni sperimentali. Questo abilita funzionalità come l'uso simultaneo di fotocamera anteriore e posteriore su dispositivi supportati.
Percorso di migrazione: Aggiornare la versione della dipendenza. Testare sui dispositivi che precedentemente avevano problemi. Le note di rilascio CameraX documentano eventuali cambiamenti comportamentali tra le versioni.
- CameraX usa il binding lifecycle-aware:
bindToLifecycle()connette gli use case sia alla fotocamera che al lifecycle dell'Activity - Le modalità ImageCapture scambiano latenza per qualità: scegliere in base allo use case, non alle capacità del dispositivo
- VideoCapture richiede il setup del Recorder prima del binding: preparare le opzioni di output prima di iniziare
- La gestione dei permessi dovrebbe spiegare lo scopo prima della richiesta: riduce i tassi di rifiuto
- CameraX 1.6 è migrato internamente a CameraPipe: nessuna modifica API richiesta, ma testare sui dispositivi target
- Le domande dei colloqui si concentrano sulla gestione del lifecycle, combinazioni di use case e confronto con Camera2
Sapresti trovare il bug in Android?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore di SharpSkill
Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.
Aggiornato il 11 settembre 2026
Condividi
Articoli correlati

Modularizzazione Android nel 2026: Architettura Multi-Modulo e Domande da Colloquio
Best practice per la modularizzazione Android con convention plugin, Gradle version catalog e feature module. Include domande da colloquio per sviluppatori senior.

Jetpack Navigation Compose nel 2026: Navigazione Type-Safe e Domande da Colloquio
Una guida completa alla navigazione type-safe con Jetpack Compose. Esempi pratici, best practice e domande frequenti nei colloqui tecnici per sviluppatori Android.

Android WorkManager nel 2026: Task in Background, Constraints e Domande da Colloquio
Guida completa ad Android WorkManager 2.11/2.12 con esempi di codice Kotlin, configurazione dei constraints, concatenazione di richieste di lavoro e domande frequenti nei colloqui tecnici.