How To Use CameraX For Camera Functions In Android
Camera features are a common part of Android apps, from identity checks and document scanning to social posts and outdoor navigation. CameraX provides a practical layer over Android’s camera hardware, helping developers support a broad range of phones without managing every Camera2 detail themselves.
For Australian users, camera applications must work across very different conditions. A person may capture a receipt in a dim Melbourne café, scan a parcel in Brisbane sunlight, or take a photo during a bushwalk outside Perth. Reliable preview, focus, exposure and image storage matter more than simply displaying a live feed.
CameraX is part of Android Jetpack and is designed around use cases. Preview displays the camera stream, ImageCapture saves still images, ImageAnalysis processes frames, and VideoCapture records video. These components can run together through a lifecycle-aware camera provider.
The phpMyAdmin notice commonly shown on a DigitalOcean Droplet is unrelated to Android development and may be only a default server setup page. The implementation below belongs in an Android Studio project, where you can test on a physical Android phone as well as an emulator.
| CameraX use case | Main purpose | Typical Australian app example | Key concern |
|---|---|---|---|
| Preview | Displays a live camera feed | Product or property inspection | Correct aspect ratio |
| ImageCapture | Takes and saves photos | Receipts, listings or ID images | File permissions and quality |
| ImageAnalysis | Reads frames in memory | QR codes or document detection | Performance and backpressure |
| VideoCapture | Records video | Training, events or field reports | Storage and battery use |
Add CameraX Dependencies
In the module-level Gradle file, add the CameraX libraries using a consistent version. The exact version may change, so use the current stable release recommended by Android’s official documentation. Common dependencies include camera-camera2, camera-lifecycle, camera-view, and camera-video when video recording is required.
dependencies {
val cameraxVersion = "1.4.2"
implementation("androidx.camera:camera-camera2:$cameraxVersion")
implementation("androidx.camera:camera-lifecycle:$cameraxVersion")
implementation("androidx.camera:camera-view:$cameraxVersion")
implementation("androidx.camera:camera-video:$cameraxVersion")
}
Add the camera permission to AndroidManifest.xml. Runtime permission approval is still required on Android 6.0 and later. Explain why the permission is needed in clear language, especially if the app handles identity documents or personal photos under Australian privacy expectations.
<uses-permission android:name="android.permission.CAMERA" />
Request Permission Safely
A camera screen should request permission before attempting to bind a camera. The Activity Result API is a clean approach because it handles the permission callback without forcing you to manage deprecated request codes.
private val cameraPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
startCamera()
} else {
Toast.makeText(
this,
"Camera access is required for scanning",
Toast.LENGTH_LONG
).show()
}
}
Call the launcher after checking ContextCompat.checkSelfPermission. If access is declined, keep the screen usable and provide a clear path to Android settings when appropriate. On a field app used around regional New South Wales or Queensland, a graceful permission state is preferable to a blank preview that appears broken.
Authentication and camera access should remain separate concerns. If the application also uses account sign-in, a Firebase sign-in guide can help establish the user session before camera data is associated with an account.
Configure Preview And Image Capture
Create a PreviewView in the layout and obtain a ProcessCameraProvider asynchronously. CameraX can then bind the preview and image capture use cases to the Activity or Fragment lifecycle.
private fun startCamera() {
val providerFuture = ProcessCameraProvider.getInstance(this)
providerFuture.addListener({
val provider = providerFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding.previewView.surfaceProvider)
}
val imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
val selector = CameraSelector.DEFAULT_BACK_CAMERA
provider.unbindAll()
provider.bindToLifecycle(
this,
selector,
preview,
imageCapture
)
this.imageCapture = imageCapture
}, ContextCompat.getMainExecutor(this))
}
Use CAPTURE_MODE_MAXIMIZE_QUALITY for documents, property listings or product images where detail matters. Minimise latency for quick snapshots. The PreviewView manages much of the surface handling, but you should still test 4:3 and 16:9 layouts on different handsets sold by Australian retailers, including budget devices with unusual screen proportions.
To capture a photo, create an output file and pass it to takePicture. Prefer app-specific external storage or MediaStore rather than writing arbitrary files to shared storage. This reduces permission complexity and makes the app behave consistently across current Android releases.
Save Photos And Handle Rotation
A simple capture method can write a JPEG to the app’s files directory:
private fun capturePhoto() {
val outputFile = File(
externalCacheDir,
"photo_${System.currentTimeMillis()}.jpg"
)
val outputOptions = ImageCapture.OutputFileOptions
.Builder(outputFile)
.build()
imageCapture?.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(
result: ImageCapture.OutputFileResults
) {
Toast.makeText(
this@MainActivity,
"Photo saved",
Toast.LENGTH_SHORT
).show()
}
override fun onError(exception: ImageCaptureException) {
Log.e("CameraX", "Capture failed", exception)
}
}
)
}
Set the target rotation from the display so images do not appear sideways when a phone changes orientation. CameraX can also apply mirroring for front-facing cameras, which is useful for previews but may be inappropriate for text or identity documents.
Avoid uploading every original image immediately. Resize or compress photos when the workflow allows it, particularly for users on limited mobile plans or patchy regional coverage. A photo taken near the Great Ocean Road should remain usable even when the network connection is intermittent.
Analyse Frames In Real Time
ImageAnalysis is suitable for QR scanning, optical character recognition and document edge detection. Configure a backpressure strategy so slow analysis does not create a growing queue of stale frames.
val analysis = ImageAnalysis.Builder()
.setBackpressureStrategy(
ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
)
.build()
analysis.setAnalyzer(cameraExecutor) { imageProxy ->
// Process imageProxy.image here
imageProxy.close()
}
Always close ImageProxy, including error paths, or the camera may eventually stop delivering frames. Run CPU-heavy work on a dedicated executor rather than the main thread. For barcode scanning, connect the frame to a suitable ML Kit analyser and convert its rotation metadata correctly.
A camera analyser should also cope with bright Australian conditions. Glare on a laminated licence in Sydney sun, shadows under a verandah in Adelaide, and low indoor light in Hobart can all reduce recognition accuracy. Give users guidance such as moving closer, holding steady or avoiding reflective angles.
Test Across Devices And Conditions
Use the rear camera for general capture and check whether the selected lens is available before binding it. Some low-cost phones expose fewer camera features, while tablets may have different sensor orientations. Test autofocus, flash behaviour, zoom, rotation and lifecycle transitions after locking and unlocking the device.
Run tests on physical devices from the local market rather than relying solely on an emulator. Include current Samsung, Google Pixel and affordable Motorola or Nokia models, then test on Wi-Fi and mobile data conditions associated with Telstra, Optus or Vodafone. Camera bugs often appear only with a particular sensor, vendor extension or aspect ratio.
Practical checks should cover both user experience and technical reliability.
Before release
- Verify permission denial and re-entry from Settings
- Test portrait, landscape and screen rotation
- Confirm photos have the correct orientation
- Check capture behaviour when storage is nearly full
During field testing
- Scan printed and reflective QR codes
- Capture images in bright sun and dim interiors
- Try slow networks and temporary offline use
- Test repeated capture without memory growth
Move From Prototype To Production
A useful camera screen needs more than a working preview. Add a visible shutter control, focus feedback, capture progress and an accessible error message. Disable the capture button briefly while saving if duplicate submissions would create problems for a booking, inspection or claims workflow.
Keep camera ownership tied to the lifecycle. Unbind use cases when leaving the screen if your architecture requires it, and shut down custom executors when they are no longer needed. Store only the images the application genuinely requires, protect sensitive content, and document retention practices for Australian customers.
Begin with Preview and ImageCapture, then add ImageAnalysis or VideoCapture only when the product needs them. Build the permission flow, test it on several Australian-market phones, and move the first CameraX screen from emulator to a real device before connecting it to production services.