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 nel 2026: Cattura Foto e Video con Domande 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.

Novità di CameraX 1.6

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.

CameraSetup.ktkotlin
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).

PhotoCaptureManager.ktkotlin
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.

VideoRecordingManager.ktkotlin
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à.

CameraPreviewComposable.ktkotlin
@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.

PermissionHandler.ktkotlin
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.

build.gradle.kts (Module: app)kotlin
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:

xml
<!-- 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:

  1. 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.

  2. 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.

  3. 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
Sfida del giorno

Sapresti trovare il bug in Android?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore 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