What is CameraX?
CameraX is a Jetpack library that makes camera development easier by providing:
- Simple camera preview
- Image capture (photos)
- Image analysis (frames for machine learning)
- Consistent behavior across different devices
- Fewer crashes compared to Camera API / Camera2
CameraX works perfectly with ML Kit for on-device AI tasks.
What is ML Kit?
ML Kit is Google’s on-device machine learning library. It’s fast, doesn’t require internet, and supports:
- Text Recognition (OCR)
- Face Detection
- Barcode Scanning
- Object Detection & Tracking
- Image Labeling
- Pose Detection
In this post, Text Recognition will be used as an example — but the same structure works for any ML Kit model.
Step-by-Step Project Guide
Step 1: Create a New Android Studio Project
- Open Android Studio (Giraffe / Koala+ recommended)
- Click New Project
- Choose Empty Activity (or Compose Activity if you're building with Jetpack Compose)
- Configure project settings:
-
- Name: SmartCameraApp
- Package: com.example.smartcamera
- Minimum SDK: Android 8.0 (API 26) or higher
- Build system: Gradle Kotlin DSL recommended
- Click Finish
The project will generate with a default MainActivity.kt.
Step 2: Add Required Dependencies
Open build.gradle (app level) and insert:
CameraX
def camerax_version = "1.3.3"
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"
implementation "androidx.camera:camera-mlkit-vision:$camerax_version"
ML Kit — Text Recognition (example)
implementation("com.google.mlkit:text-recognition:16.0.1")
Step 3: Add Camera Permission
Add the permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
Request it at runtime using the Activity Result API.
Step 4: Add a Camera Preview UI
Open activity_main.xml:
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
PreviewView is the recommended CameraX preview component.
Step 5: Request Camera Permission
In MainActivity.kt:
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) startCamera()
else Toast.makeText(this, "Camera permission required.", Toast.LENGTH_LONG).show()
}
private fun requestCameraPermission() {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
Call requestCameraPermission() inside onCreate().
Step 6: Start CameraX
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
// Preview setup
val preview = Preview.Builder().build().apply {
setSurfaceProvider(findViewById<PreviewView>(R.id.previewView).surfaceProvider)
}
// Image analysis setup
val analysis = ImageAnalysis.Builder()
.setTargetResolution(Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.apply {
setAnalyzer(
Executors.newSingleThreadExecutor(),
MlKitAnalyzer()
)
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
analysis
)
}, ContextCompat.getMainExecutor(this))
}
Step 7: Implement the ML Kit Analyzer
Create a new file MlKitAnalyzer.kt
class MlKitAnalyzer : ImageAnalysis.Analyzer {
private val recognizer = TextRecognition.getClient()
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: return
val rotation = imageProxy.imageInfo.rotationDegrees
val inputImage = InputImage.fromMediaImage(mediaImage, rotation)
recognizer.process(inputImage)
.addOnSuccessListener { result ->
Log.d("MLKit", "Detected Text: ${result.text}")
}
.addOnFailureListener { e ->
Log.e("MLKit", "Error: ${e.localizedMessage}")
}
.addOnCompleteListener {
imageProxy.close()
}
}
}
Step 8: Optional Overlay Rendering
(Used for bounding boxes, detection highlights, face frames)
Overlay View (optional)
class OverlayView(context: Context, attrs: AttributeSet? = null) : View(context, attrs) {
var boxes: List<Rect> = emptyList()
set(value) {
field = value
invalidate()
}
private val paint = Paint().apply {
color = Color.GREEN
style = Paint.Style.STROKE
strokeWidth = 4f
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
boxes.forEach { canvas.drawRect(it, paint) }
}
}
Add to layout:
<com.example.smartcamera.OverlayView
android:id="@+id/overlayView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Step 9: Performance and Architecture Considerations
- Use a single analyzer thread: Using Executors.newSingleThreadExecutor() prevents backpressure.
- Set appropriate resolution: 1280×720 provides a balance of speed and detail.
- Reuse ML Kit detector: Avoid creating new ML Kit instances per frame.
- Move ML logic into a ViewModel for large apps: Ensures clean architecture and testability.
Conclusion
By combining CameraX with ML Kit, Android developers can build intelligent, production-ready camera applications with minimal complexity. The stack provides:
- A modern, reliable camera pipeline.
- High-performance on-device ML processing.
- Clean integration with Jetpack architecture components.
- Flexibility for a range of detection and recognition tasks.
This approach is ideal for apps involving OCR, barcode scanning, identity verification, inventory automation, smart forms, and more.
Ready to get started?
Contact IVC for a free consultation and discover how we can help your business grow online.
Contact IVC for a Free ConsultationReference:
https://developer.android.com/media/camera/camerax
https://developers.google.com/ml-kit/guides


