# Android CameraX 2026年完全ガイド:写真・動画撮影と面接対策質問集 > CameraX 1.6による写真撮影・動画録画の実装方法を解説。Jetpack Compose統合、パーミッション処理、Android開発者面接でよく聞かれるCameraX質問と回答例を紹介します。 - Published: 2026-09-11 - Updated: 2026-09-11 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Android CameraXは、ライフサイクル対応APIによってハードウェアの複雑さを抽象化し、カメラ開発を大幅に簡素化します。バージョン1.6.2が安定版としてリリースされ、CameraPipeへの移行が完了した現在、CameraXはPixelカメラアプリと同じ高性能カメラスタックを提供しています。 > **CameraX 1.6の主要な変更点** > > CameraX 1.6ではCameraPipeへの移行、VideoCaptureにおけるMedia3 Muxerのデフォルト採用、SessionConfig APIの安定化が実現しました。Kotlin DSLビルダー(`preview { }`、`imageCapture { }`、`videoCapture { }`)により、ボイラープレートコードが40%削減されます。 ## CameraXのアーキテクチャとユースケースモデル CameraXは、同時に実行可能な4つの主要ユースケースを提供します:Preview、ImageCapture、ImageAnalysis、VideoCapture。各ユースケースは[LifecycleOwner](https://developer.android.com/topic/libraries/architecture/lifecycle)にバインドされるため、カメラはActivityやFragmentと連動して自動的に開始・停止します。 CameraProviderはこれらのユースケースをインスタンス化し、カメラにバインドするファクトリとして機能します。この疎結合により、ベンダー固有の問題を心配することなく、異なるOEMのデバイスで同じコードが動作します。 ```kotlin // CameraSetup.kt class CameraSetup( private val context: Context, private val lifecycleOwner: LifecycleOwner ) { private lateinit var cameraProvider: ProcessCameraProvider private var imageCapture: ImageCapture? = null private var videoCapture: VideoCapture? = 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 ) } } ``` `bindToLifecycle`の呼び出しは、ユースケースをカメラハードウェアとライフサイクルの両方に接続します。LifecycleOwnerがSTARTED状態になるとカメラが開き、STOPPED状態になると自動的に閉じます。 ## ImageCaptureによる写真撮影の実装 ImageCaptureは2つのキャプチャモードを提供します:高速シャッターレスポンス用の`CAPTURE_MODE_MINIMIZE_LATENCY`と、処理負荷の高い撮影用の`CAPTURE_MODE_MAXIMIZE_QUALITY`。選択は、アプリが速度(SNSアプリ)を優先するか品質(ドキュメントスキャナー)を優先するかによって決まります。 ```kotlin // PhotoCaptureManager.kt 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ではDNG(RAW)キャプチャのサポートが追加され、未処理のセンサーデータを必要とするアプリに対応しています。RAW出力を有効にする前に、`ImageCapture.getImageCaptureCapabilities()`でデバイスの機能を確認してください。 ## VideoCaptureとRecorderによる動画録画 VideoCaptureは[Recorder](https://developer.android.com/reference/androidx/camera/video/Recorder)オブジェクトを使用してエンコードとマルチプレクシングを処理します。Recorder APIは、音声同期を自動的に処理するprepare-start-stopパターンに従います。 ```kotlin // VideoRecordingManager.kt class VideoRecordingManager( private val context: Context, private val videoCapture: VideoCapture ) { 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ではスローモーション動画のサポートが追加されました。120fpsまたは240fps録画を有効にする前に、`Recorder.getHighSpeedVideoCapabilities()`で機能を確認してください。 ## Jetpack ComposeでのCameraX統合 CameraX 1.5では`camera-compose`アーティファクトと`CameraXViewfinder`コンポーザブルが導入されました。ViewベースのPreviewViewを使用しているアプリでは、AndroidViewが相互運用を提供します。 ```kotlin // CameraPreviewComposable.kt @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" ) } } } } ``` Compose優先の実装については、[Jetpack Composeの面接質問集](/technologies/android/interview-questions/android-compose)がカメラ状態管理に直接適用できるViewModel統合パターンを解説しています。 ## カメラパーミッションの処理 AndroidではCAMERAパーミッションの実行時取得が必要です。RECORD_AUDIOは音声付きの動画録画時のみ必要です。パーミッションフローでは、リクエスト前にアクセスが必要な理由を説明する必要があります。 ```kotlin // PermissionHandler.kt 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) } } } ``` ## CameraXの面接質問 CameraXは、カメラ統合、ライフサイクル管理、ハードウェア抽象化について議論する際にAndroid面接で取り上げられます。これらの質問は、アーキテクチャと実践的な実装詳細の理解度をテストします。 ### Camera2の代わりにCameraXを使用する理由 CameraXは、Camera2が直接公開するデバイス固有の問題を抽象化します。Camera2の実装では、何百ものデバイス固有の回避策を処理する必要があります。CameraXはこれらの修正をライブラリに組み込み、150以上のデバイスモデルをカバーする[CameraX Test Lab](https://android-developers.googleblog.com/2025/11/introducing-camerax-15-powerful-video.html)でテストされています。 ライフサイクル対応バインディングにより、手動でのリソース管理が不要になります。Camera2では、すべてのライフサイクルコールバックで正しく処理されないとリークを引き起こす明示的なopen/close呼び出しが必要です。 ### CameraProviderはどのようにユースケースをライフサイクルにバインドするか CameraProviderは内部的にLifecycleObserverパターンを使用します。`bindToLifecycle()`を呼び出すと、提供されたLifecycleOwnerにオブザーバーを登録します。このオブザーバーはON_STARTとON_STOPイベントを受け取り、カメラを開閉します。 重要なポイント:CameraXはバインド時に即座にカメラを開始しません。ライフサイクルがSTARTED状態に達するまで待機し、これはActivity.onStart()のタイミングと一致します。 ### 互換性のないユースケースをバインドするとどうなるか すべてのユースケースの組み合わせがすべてのデバイスで動作するわけではありません。Preview + VideoCapture + ImageAnalysis + ImageCaptureは古いハードウェアでは失敗する可能性があります。CameraXは実行時ではなく、バインド時にIllegalArgumentExceptionをスローします。 解決策は、複雑な組み合わせをバインドする前に`CameraProvider.hasCamera()`とデバイスの機能を確認することです。重要なアプリでは、ローエンドデバイスで明示的にテストしてください。 ### CAPTURE_MODE_MINIMIZE_LATENCYとCAPTURE_MODE_MAXIMIZE_QUALITYの違い MINIMIZE_LATENCYは、より高速な処理パイプラインを使用し、一部の後処理をスキップする可能性があることでシャッターラグを削減します。MAXIMIZE_QUALITYは、対応デバイスで完全なHDR+処理、ノイズリダクション、マルチフレームキャプチャを適用します。 トレードオフ:レイテンシモードは100-200msでキャプチャし、クオリティモードは照明条件によって500ms-1sかかる場合があります。SNSアプリは通常レイテンシを選択し、ドキュメントスキャンアプリはクオリティを選択します。 ### CameraXはデバイスの回転をどのように処理するか CameraXはターゲット回転設定を通じて回転を自動的に処理します。デフォルトではディスプレイの回転を使用しますが、アプリは`setTargetRotation()`でオーバーライドできます。出力画像のEXIFデータには正しい向きタグが含まれます。 PreviewViewの場合、scaleTypeがアスペクト比の違いを処理します。FILL_CENTERは塗りつぶすためにクロップし、FIT_CENTERはレターボックスを表示します。選択は、アプリがフルスクリーンプレビューを優先するか、クロッピングを避けることを優先するかによって決まります。 ## CameraX 1.6の依存関係とセットアップ CameraXライブラリは複数のアーティファクトに分割されています。APKサイズを最小化するために、アプリが使用するものだけを含めてください。 ```kotlin // build.gradle.kts (Module: app) 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 } } ``` マニフェストには機能宣言とパーミッションが必要です: ```xml ``` CameraXのListenableFuture呼び出しをsuspend関数でラップする際には、[Kotlin Coroutines](/blog/android/mastering-kotlin-coroutines)の関連パターンが適用されます。 ## CameraX 1.6が本番アプリに与える影響 CameraX 1.6は、既存の実装に影響を与える3つの変更をもたらしました: 1. **CameraPipeバックエンド**:内部カメラスタックがPixelカメラと同じアーキテクチャであるCameraPipeを使用するようになりました。これによりPixelデバイスでのパフォーマンスが向上し、高度な機能のためのより清潔な基盤が提供されます。既存のコードに変更は必要ありません。 2. **Media3 Muxerのデフォルト化**:VideoCaptureがMediaMuxerの代わりにMedia3 Muxerを使用するようになりました。これによりクラッシュ耐性が向上し、録画中にアプリが終了しても動画ファイルは再生可能なままです。APIサーフェスに変更はありません。 3. **SessionConfig APIの安定化**:アプリはexperimentalアノテーションなしでSessionConfigを通じて高度なカメラ設定を構成できるようになりました。これにより、対応デバイスでの前面/背面カメラの同時使用などの機能が可能になります。 **移行パス**:依存関係のバージョンを更新します。以前問題があったデバイスでテストします。[CameraXリリースノート](https://developer.android.com/jetpack/androidx/releases/camera)にバージョン間の動作変更が記載されています。 - CameraXはライフサイクル対応バインディングを使用:`bindToLifecycle()`はユースケースをカメラとActivityライフサイクルの両方に接続 - ImageCaptureモードはレイテンシと品質のトレードオフ:デバイスの機能ではなくユースケースに基づいて選択 - VideoCaptureはバインド前にRecorderのセットアップが必要:開始前に出力オプションを準備 - パーミッション処理はリクエスト前に目的を説明:拒否率を削減 - CameraX 1.6は内部的にCameraPipeに移行:API変更は不要だが、ターゲットデバイスでテストが必要 - 面接質問はライフサイクル管理、ユースケースの組み合わせ、Camera2との比較に焦点 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/ja/blog/android/camerax-photo-video-capture-interview-questions