Android CameraX 2026年完全ガイド:写真・動画撮影と面接対策質問集
CameraX 1.6による写真撮影・動画録画の実装方法を解説。Jetpack Compose統合、パーミッション処理、Android開発者面接でよく聞かれるCameraX質問と回答例を紹介します。

Android CameraXは、ライフサイクル対応APIによってハードウェアの複雑さを抽象化し、カメラ開発を大幅に簡素化します。バージョン1.6.2が安定版としてリリースされ、CameraPipeへの移行が完了した現在、CameraXはPixelカメラアプリと同じ高性能カメラスタックを提供しています。
CameraX 1.6ではCameraPipeへの移行、VideoCaptureにおけるMedia3 Muxerのデフォルト採用、SessionConfig APIの安定化が実現しました。Kotlin DSLビルダー(preview { }、imageCapture { }、videoCapture { })により、ボイラープレートコードが40%削減されます。
CameraXのアーキテクチャとユースケースモデル
CameraXは、同時に実行可能な4つの主要ユースケースを提供します:Preview、ImageCapture、ImageAnalysis、VideoCapture。各ユースケースはLifecycleOwnerにバインドされるため、カメラはActivityやFragmentと連動して自動的に開始・停止します。
CameraProviderはこれらのユースケースをインスタンス化し、カメラにバインドするファクトリとして機能します。この疎結合により、ベンダー固有の問題を心配することなく、異なるOEMのデバイスで同じコードが動作します。
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
)
}
}bindToLifecycleの呼び出しは、ユースケースをカメラハードウェアとライフサイクルの両方に接続します。LifecycleOwnerがSTARTED状態になるとカメラが開き、STOPPED状態になると自動的に閉じます。
ImageCaptureによる写真撮影の実装
ImageCaptureは2つのキャプチャモードを提供します:高速シャッターレスポンス用のCAPTURE_MODE_MINIMIZE_LATENCYと、処理負荷の高い撮影用のCAPTURE_MODE_MAXIMIZE_QUALITY。選択は、アプリが速度(SNSアプリ)を優先するか品質(ドキュメントスキャナー)を優先するかによって決まります。
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オブジェクトを使用してエンコードとマルチプレクシングを処理します。Recorder APIは、音声同期を自動的に処理するprepare-start-stopパターンに従います。
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ではスローモーション動画のサポートが追加されました。120fpsまたは240fps録画を有効にする前に、Recorder.getHighSpeedVideoCapabilities()で機能を確認してください。
Androidの面接対策はできていますか?
インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。
Jetpack ComposeでのCameraX統合
CameraX 1.5ではcamera-composeアーティファクトとCameraXViewfinderコンポーザブルが導入されました。ViewベースのPreviewViewを使用しているアプリでは、AndroidViewが相互運用を提供します。
@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の面接質問集がカメラ状態管理に直接適用できるViewModel統合パターンを解説しています。
カメラパーミッションの処理
AndroidではCAMERAパーミッションの実行時取得が必要です。RECORD_AUDIOは音声付きの動画録画時のみ必要です。パーミッションフローでは、リクエスト前にアクセスが必要な理由を説明する必要があります。
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でテストされています。
ライフサイクル対応バインディングにより、手動でのリソース管理が不要になります。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サイズを最小化するために、アプリが使用するものだけを含めてください。
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
}
}マニフェストには機能宣言とパーミッションが必要です:
<!-- 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>CameraXのListenableFuture呼び出しをsuspend関数でラップする際には、Kotlin Coroutinesの関連パターンが適用されます。
今すぐ練習を始めましょう!
面接シミュレーターと技術テストで知識をテストしましょう。
CameraX 1.6が本番アプリに与える影響
CameraX 1.6は、既存の実装に影響を与える3つの変更をもたらしました:
-
CameraPipeバックエンド:内部カメラスタックがPixelカメラと同じアーキテクチャであるCameraPipeを使用するようになりました。これによりPixelデバイスでのパフォーマンスが向上し、高度な機能のためのより清潔な基盤が提供されます。既存のコードに変更は必要ありません。
-
Media3 Muxerのデフォルト化:VideoCaptureがMediaMuxerの代わりにMedia3 Muxerを使用するようになりました。これによりクラッシュ耐性が向上し、録画中にアプリが終了しても動画ファイルは再生可能なままです。APIサーフェスに変更はありません。
-
SessionConfig APIの安定化:アプリはexperimentalアノテーションなしでSessionConfigを通じて高度なカメラ設定を構成できるようになりました。これにより、対応デバイスでの前面/背面カメラの同時使用などの機能が可能になります。
移行パス:依存関係のバージョンを更新します。以前問題があったデバイスでテストします。CameraXリリースノートにバージョン間の動作変更が記載されています。
- CameraXはライフサイクル対応バインディングを使用:
bindToLifecycle()はユースケースをカメラとActivityライフサイクルの両方に接続 - ImageCaptureモードはレイテンシと品質のトレードオフ:デバイスの機能ではなくユースケースに基づいて選択
- VideoCaptureはバインド前にRecorderのセットアップが必要:開始前に出力オプションを準備
- パーミッション処理はリクエスト前に目的を説明:拒否率を削減
- CameraX 1.6は内部的にCameraPipeに移行:API変更は不要だが、ターゲットデバイスでテストが必要
- 面接質問はライフサイクル管理、ユースケースの組み合わせ、Camera2との比較に焦点
Android のバグを見つけられますか
実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

執筆
Anthony Fillion-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年9月11日 更新
共有
関連記事

2026年のAndroidモジュール化:マルチモジュールアーキテクチャと面接対策
Androidアプリのマルチモジュール設計について詳しく解説。Gradleバージョンカタログ、コンベンションプラグイン、モジュール間通信パターン、そして技術面接でよく出題される質問と回答を紹介します。

Jetpack Navigation Compose 2026年版:型安全ナビゲーションと面接対策
Navigation Compose 2.10の型安全APIを詳細解説。Kotlin Serializationによるルート定義、ネストグラフ、ディープリンク、面接頻出質問まで網羅。

Android WorkManager 2026年完全ガイド:バックグラウンドタスク、制約条件、面接対策
Android WorkManagerを使ったバックグラウンド処理の実装方法を詳しく解説。制約条件の設定、定期実行、チェーン処理、2026年の技術面接でよく問われる質問まで網羅的にカバー。