Android CameraX 2026: Panduan Lengkap Pengambilan Foto dan Video dengan Pertanyaan Wawancara
Pelajari CameraX di Android 2026: pengambilan foto, perekaman video, integrasi Jetpack Compose, dan pertanyaan wawancara teknis untuk developer Android.

Android CameraX menyederhanakan pengembangan kamera dengan mengabstraksi kompleksitas hardware melalui API yang lifecycle-aware. Dengan versi 1.6.2 yang kini stabil dan migrasi ke CameraPipe yang telah selesai, CameraX menghadirkan stack kamera berperforma tinggi yang sama dengan yang digunakan pada aplikasi kamera Pixel.
CameraX 1.6 bermigrasi ke CameraPipe, menggunakan Media3 Muxer secara default untuk VideoCapture, dan menstabilkan SessionConfig API. Kotlin DSL builders (preview { }, imageCapture { }, videoCapture { }) mengurangi boilerplate hingga 40%.
Arsitektur CameraX dan Model Use Case
CameraX menyediakan empat use case utama yang dapat berjalan secara bersamaan: Preview, ImageCapture, ImageAnalysis, dan VideoCapture. Setiap use case terhubung ke LifecycleOwner, sehingga kamera secara otomatis mulai dan berhenti mengikuti activity atau fragment.
CameraProvider bertindak sebagai factory yang membuat instance use case dan mengikatnya ke kamera. Pemisahan ini memastikan kode yang sama berjalan di perangkat dari berbagai OEM tanpa perlu khawatir tentang keunikan vendor tertentu.
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 binds use cases to lifecycle
cameraProvider = ProcessCameraProvider.getInstance(context).await()
}
fun bindUseCases(previewView: PreviewView) {
// Unbind existing use cases before rebinding
cameraProvider.unbindAll()
// Preview use case displays camera feed
val preview = Preview.Builder()
.build()
.apply { setSurfaceProvider(previewView.surfaceProvider) }
// ImageCapture for photos
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
// VideoCapture with Recorder
val recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(Quality.FHD))
.build()
videoCapture = VideoCapture.withOutput(recorder)
// Bind all use cases to lifecycle
cameraProvider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
imageCapture,
videoCapture
)
}
}Pemanggilan bindToLifecycle menghubungkan use case ke hardware kamera dan lifecycle sekaligus. Ketika LifecycleOwner memasuki state STARTED, kamera terbuka. Ketika memasuki STOPPED, kamera menutup secara otomatis.
Implementasi Pengambilan Foto dengan ImageCapture
ImageCapture menyediakan dua capture mode: CAPTURE_MODE_MINIMIZE_LATENCY untuk respons shutter yang cepat, dan CAPTURE_MODE_MAXIMIZE_QUALITY untuk pengambilan dengan pemrosesan intensif. Pilihan tergantung pada apakah aplikasi mengutamakan kecepatan (aplikasi sosial) atau kualitas (pemindai dokumen).
class PhotoCaptureManager(
private val context: Context,
private val imageCapture: ImageCapture
) {
private val mainExecutor = ContextCompat.getMainExecutor(context)
fun capturePhoto(onResult: (Uri?) -> Unit) {
// Generate unique filename with timestamp
val filename = "IMG_\${System.currentTimeMillis()}.jpg"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
// Store in Pictures/CameraX folder on 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 contains the MediaStore URI
onResult(results.savedUri)
}
override fun onError(exception: ImageCaptureException) {
Log.e("PhotoCapture", "Capture failed: \${exception.message}")
onResult(null)
}
}
)
}
}CameraX 1.5 menambahkan dukungan capture DNG (RAW) untuk aplikasi yang membutuhkan data sensor mentah. Periksa kemampuan perangkat dengan ImageCapture.getImageCaptureCapabilities() sebelum mengaktifkan output RAW.
Merekam Video dengan VideoCapture dan Recorder
VideoCapture menggunakan objek Recorder untuk menangani encoding dan muxing. Recorder API mengikuti pola prepare-start-stop yang menangani sinkronisasi audio secara otomatis.
class VideoRecordingManager(
private val context: Context,
private val videoCapture: VideoCapture<Recorder>
) {
private var activeRecording: Recording? = null
fun startRecording(onEvent: (VideoRecordEvent) -> Unit): Boolean {
// Check if already recording
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()
// Prepare recording with audio if permission granted
val pendingRecording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
if (hasAudioPermission()) {
pendingRecording.withAudioEnabled()
}
// Start recording and store reference
activeRecording = pendingRecording.start(
ContextCompat.getMainExecutor(context)
) { event ->
onEvent(event)
// Clear reference when recording completes
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 menambahkan dukungan video slow-motion. Query kemampuan dengan Recorder.getHighSpeedVideoCapabilities() sebelum mengaktifkan perekaman 120fps atau 240fps.
Siap menguasai wawancara Android Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
CameraX dengan Jetpack Compose
CameraX 1.5 memperkenalkan artefak camera-compose dengan composable CameraXViewfinder. Untuk aplikasi yang masih menggunakan PreviewView berbasis View, AndroidView menyediakan interoperabilitas.
@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)
}
)
// Capture buttons overlay
Row(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(32.dp),
horizontalArrangement = Arrangement.spacedBy(24.dp)
) {
IconButton(
onClick = { viewModel.capturePhoto() }
) {
Icon(Icons.Default.Camera, "Take photo")
}
IconButton(
onClick = { viewModel.toggleRecording() }
) {
Icon(
if (viewModel.isRecording) Icons.Default.Stop
else Icons.Default.Videocam,
"Record video"
)
}
}
}
}Untuk implementasi yang mengutamakan Compose, panduan pertanyaan wawancara Jetpack Compose mencakup pola integrasi ViewModel yang dapat diterapkan langsung pada manajemen state kamera.
Menangani Izin Kamera
Android memerlukan izin CAMERA saat runtime. RECORD_AUDIO hanya diperlukan saat merekam video dengan suara. Alur izin harus menjelaskan mengapa akses diperlukan sebelum meminta.
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)
}
}
}Pertanyaan Wawancara CameraX
CameraX sering muncul dalam wawancara Android saat membahas integrasi kamera, manajemen lifecycle, atau abstraksi hardware. Pertanyaan-pertanyaan ini menguji pemahaman tentang arsitektur dan detail implementasi praktis.
Mengapa menggunakan CameraX daripada Camera2?
CameraX mengabstraksi keunikan perangkat yang langsung diekspos oleh Camera2. Implementasi Camera2 memerlukan penanganan ratusan workaround khusus perangkat. CameraX menyematkan perbaikan ini ke dalam library, yang diuji terhadap CameraX Test Lab yang mencakup lebih dari 150 model perangkat.
Binding yang lifecycle-aware menghilangkan kebutuhan manajemen resource secara manual. Camera2 memerlukan panggilan open/close eksplisit yang menyebabkan kebocoran memori jika tidak ditangani dengan benar di setiap callback lifecycle.
Bagaimana CameraProvider mengikat use case ke lifecycle?
CameraProvider menggunakan pola LifecycleObserver secara internal. Saat memanggil bindToLifecycle(), ia mendaftarkan observer pada LifecycleOwner yang diberikan. Observer ini menerima event ON_START dan ON_STOP untuk membuka dan menutup kamera.
Insight utama: CameraX tidak langsung memulai kamera saat binding. Ia menunggu lifecycle mencapai state STARTED, yang sesuai dengan waktu Activity.onStart().
Apa yang terjadi saat mengikat use case yang tidak kompatibel?
Tidak semua kombinasi use case berfungsi di semua perangkat. Preview + VideoCapture + ImageAnalysis + ImageCapture mungkin gagal pada hardware lama. CameraX melempar IllegalArgumentException saat binding, bukan saat runtime.
Solusinya adalah memeriksa CameraProvider.hasCamera() dan kemampuan perangkat sebelum mengikat kombinasi kompleks. Untuk aplikasi kritis, uji secara eksplisit pada perangkat low-end.
Jelaskan perbedaan antara CAPTURE_MODE_MINIMIZE_LATENCY dan CAPTURE_MODE_MAXIMIZE_QUALITY
MINIMIZE_LATENCY mengurangi lag shutter dengan menggunakan pipeline pemrosesan yang lebih cepat, mungkin melewatkan beberapa post-processing. MAXIMIZE_QUALITY menerapkan pemrosesan HDR+ penuh, pengurangan noise, dan multi-frame capture pada perangkat yang didukung.
Tradeoff-nya: mode latency mengambil gambar dalam 100-200ms, mode quality mungkin membutuhkan 500ms-1s tergantung pencahayaan. Aplikasi sosial biasanya memilih latency. Aplikasi pemindai dokumen memilih quality.
Bagaimana CameraX menangani rotasi perangkat?
CameraX secara otomatis menangani rotasi melalui pengaturan target rotation. Secara default, ia menggunakan rotasi Display, tetapi aplikasi dapat menimpa dengan setTargetRotation(). Data EXIF gambar output berisi tag orientasi yang benar.
Untuk PreviewView, scaleType menangani perbedaan aspek rasio. FILL_CENTER memotong untuk mengisi, FIT_CENTER menampilkan letterboxing. Pilihan tergantung pada apakah aplikasi mengutamakan preview layar penuh atau menghindari pemotongan.
Dependensi dan Setup untuk CameraX 1.6
Library CameraX dibagi menjadi beberapa artefak. Sertakan hanya yang digunakan aplikasi untuk meminimalkan ukuran APK.
dependencies {
val cameraxVersion = "1.6.2"
// Core library required for all use cases
implementation("androidx.camera:camera-core:\$cameraxVersion")
// Camera2 implementation (required)
implementation("androidx.camera:camera-camera2:\$cameraxVersion")
// Lifecycle integration
implementation("androidx.camera:camera-lifecycle:\$cameraxVersion")
// VideoCapture use case
implementation("androidx.camera:camera-video:\$cameraxVersion")
// PreviewView and camera UI components
implementation("androidx.camera:camera-view:\$cameraxVersion")
// Optional: Extensions (Night mode, HDR, etc.)
implementation("androidx.camera:camera-extensions:\$cameraxVersion")
// Optional: Real-time effects
implementation("androidx.camera:camera-effects:\$cameraxVersion")
}
android {
// CameraX requires Java 11 bytecode
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}Manifest memerlukan deklarasi fitur dan izin:
<!-- AndroidManifest.xml -->
<manifest>
<!-- Camera hardware requirement -->
<uses-feature android:name="android.hardware.camera.any" />
<!-- Runtime permissions -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>Pola terkait untuk Kotlin Coroutines berlaku saat membungkus panggilan ListenableFuture CameraX dalam fungsi suspend.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Perubahan CameraX 1.6 untuk Aplikasi Produksi
CameraX 1.6 membawa tiga perubahan yang mempengaruhi implementasi yang ada:
-
Backend CameraPipe: Stack kamera internal sekarang menggunakan CameraPipe, arsitektur yang sama dengan kamera Pixel. Ini meningkatkan performa pada perangkat Pixel dan menyediakan fondasi yang lebih bersih untuk fitur lanjutan. Kode yang ada tidak perlu perubahan.
-
Media3 Muxer default: VideoCapture sekarang menggunakan Media3 Muxer sebagai pengganti MediaMuxer. Ini meningkatkan ketahanan terhadap crash: jika aplikasi berhenti selama perekaman, file video tetap dapat diputar. Permukaan API tidak berubah.
-
SessionConfig API stabil: Aplikasi sekarang dapat mengkonfigurasi pengaturan kamera lanjutan melalui SessionConfig tanpa anotasi experimental. Ini memungkinkan fitur seperti penggunaan kamera depan/belakang secara simultan pada perangkat yang didukung.
Jalur migrasi: Perbarui versi dependensi. Uji pada perangkat yang sebelumnya memiliki masalah. Catatan rilis CameraX mendokumentasikan perubahan perilaku antar versi.
- CameraX menggunakan binding lifecycle-aware:
bindToLifecycle()menghubungkan use case ke kamera dan lifecycle Activity - Mode ImageCapture menukar latency dengan kualitas: pilih berdasarkan use case, bukan kemampuan perangkat
- VideoCapture memerlukan setup Recorder sebelum binding: siapkan opsi output sebelum memulai
- Penanganan izin harus menjelaskan tujuan sebelum meminta: mengurangi tingkat penolakan
- CameraX 1.6 bermigrasi ke CameraPipe secara internal: tidak ada perubahan API yang diperlukan, tetapi uji pada perangkat target
- Pertanyaan wawancara fokus pada manajemen lifecycle, kombinasi use case, dan perbandingan dengan Camera2
Bisakah kamu menemukan bug di Android?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 11 September 2026
Bagikan
Artikel terkait

Modularisasi Android 2026: Arsitektur Multi-Modul dan Pertanyaan Interview
Kuasai arsitektur multi-modul Android dengan convention plugins, Gradle version catalogs, dan feature modules. Termasuk pertanyaan interview umum tentang strategi modularisasi.

Jetpack Navigation Compose 2026: Navigasi Type-Safe dan Pertanyaan Interview
Pelajari Jetpack Navigation Compose 2.10 dengan navigasi type-safe menggunakan Kotlin Serialization. Panduan lengkap dengan contoh kode dan pertanyaan interview Android.

Android WorkManager 2026: Panduan Lengkap Background Tasks, Constraints, dan Pertanyaan Interview
Pelajari Android WorkManager untuk menjalankan background tasks dengan constraints, chaining, dan CoroutineWorker. Termasuk pertanyaan interview untuk persiapan wawancara kerja Android developer.