Combining Compose with CameraX Preview
约 313 字大约 1 分钟
Android
2025-12-23
1. Background
After permission is granted, the next step is to show a live rear camera preview.
CameraX officially recommends using PreviewView as the preview widget, but Jetpack Compose does not yet provide a native camera container.
So we need to embed a traditional Android View inside Compose using AndroidView.
This note focuses on integrating CameraX preview with Compose UI.
2. PreviewView and AndroidView
1. PreviewView
- CameraX’s official preview widget
- renders camera frame data
- must be bound to a CameraX
Previewuse case
2. AndroidView
AndroidView(
factory = { context ->
// return a traditional Android View
},
modifier = Modifier.fillMaxSize()
)AndroidView allows Compose to host any traditional Android view, including PreviewView.
3. CameraX initialization and callback
val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
activity,
cameraSelector,
preview
)
} catch (e: Exception) {
e.printStackTrace()
}
}, ContextCompat.getMainExecutor(ctx))Key points
ProcessCameraProvider.getInstance(ctx)gets a CameraX provider asynchronouslyaddListener({ ... }, executor)runs a callback when it is readysetSurfaceProviderbinds preview output toPreviewViewbindToLifecycleties the use case to the activity lifecycleunbindAll()clears old bindings
4. Full CameraPreview example
@Composable
fun CameraPreview(activity: ComponentActivity) {
val context = LocalContext.current
AndroidView(
factory = { ctx ->
val previewView = PreviewView(ctx)
val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
activity,
cameraSelector,
preview
)
} catch (e: Exception) {
e.printStackTrace()
}
}, ContextCompat.getMainExecutor(ctx))
previewView
},
modifier = Modifier.fillMaxSize()
)
}Summary
AndroidView + PreviewViewembeds CameraX preview into Compose- callbacks handle asynchronous initialization
- lifecycle binding lets CameraX manage the camera automatically
5. What I learned
AndroidViewis the bridge between Compose and traditional ViewsPreview,CameraProvider, andCameraSelectorare the core CameraX concepts- Callbacks are how async CameraX initialization fits into Compose
