AndroidのカメラをUIに表示する【Androidアプリ開発】
AndroidのカメラをUIに表示するソースコードを解説します。UIは、 Composable を使って構成します。
ソースコード
AndroidManifest.xml
AndroidManifest.xml に以下を追加します。xml
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
build.gradle.kts (Module :app)
モジュールレベルの build.gradle.kts の dependencies に以下を追加して、依存ライブラリをインストールします。
kts
implementation("androidx.camera:camera-camera2:1.3.1")
implementation("androidx.camera:camera-lifecycle:1.3.1")
implementation("androidx.camera:camera-view:1.3.1")
MainActivity
kotlin
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
RtmpTestTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
// CameraPreview() に hasCameraPermission を渡します
CameraPreviewWithPermissionRequest()
}
}
}
}
}
@Composable
fun CameraPreviewWithPermissionRequest() {
var hasCameraPermission by remember { mutableStateOf(false) }
val context = LocalContext.current
// パーミッションのリクエストの結果を受け取る Launcher
val permissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { isGranted: Boolean ->
hasCameraPermission = isGranted
}
)
// アプリがフォアグラウンドに来たときにパーミッションの状態をチェック
LaunchedEffect(key1 = true) {
if (context.checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissionLauncher.launch(android.Manifest.permission.CAMERA)
} else {
hasCameraPermission = true
}
}
if (hasCameraPermission) {
CameraPreview()
} else {
Text("カメラのアクセス許可が必要です。")
}
}
CameraPreview.kt
kotlin
@Composable
fun CameraPreview() {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
val previewView = remember { PreviewView(context) } // CameraXライブラリの一部で、カメラのプレビューを表示するためのビュー
val modifier = Modifier.fillMaxSize()
AndroidView(
modifier = modifier,
factory = { previewView },
update = { view ->
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(view.surfaceProvider)
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, preview
)
} catch(exc: Exception) {
Log.e("CameraPreview", "Use case binding failed", exc)
}
}
)
}
解説
このコードは、AndroidのJetpack Composeを使用して、カメラのプレビューを表示するためのComposable関数(CameraPreview)を定義しています。Composable関数は、UIを宣言的に記述するためのもので、Jetpack Composeで使用されます。この特定の例では、カメラのプレビューを画面に表示するために、CameraXライブラリと一緒に使用されています。
ここで重要なクラスと関数について解説します:
PreviewView
PreviewViewは、CameraXライブラリの一部で、カメラのプレビューを表示するためのビューです。Androidの従来のビューシステムに属しており、Compose内で使用するためには、AndroidViewというComposable関数を介して統合する必要があります。AndroidView
AndroidViewは、既存のAndroidビュー(この場合はPreviewView)をComposeに統合するために使用されるComposable関数です。これにより、Composeが中心のアプリケーションでも、まだComposeに移行されていない旧式のビューコンポーネントを使用できるようになります。コード解説
ローカルコンテキストとライフサイクルオーナーの取得
kotlin
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
Compose内で、現在のコンテキストとライフサイクルオーナーを取得しています。これらはカメラのセットアップとバインディングに必要です。
CameraProviderの取得とPreviewViewのインスタンス化
kotlin
rememberを使用して、ProcessCameraProviderのインスタンス(将来的な結果を含む)とPreviewViewのインスタンスを保持します。これにより、これらのオブジェクトは、Composableが再構築されるたびに再インスタンス化されることはありません。val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
val previewView = remember { PreviewView(context) }
AndroidViewを使ってPreviewViewをComposeに統合
kotlin
AndroidView Composableは、PreviewViewをComposeのUIツリーに統合します。factoryパラメータにはPreviewViewのインスタンスを渡し、updateブロックでは、カメラのセットアップとバインディングのロジックを記述します。AndroidView(
modifier = modifier,
factory = { previewView },
update = { view ->
// ...
}
)
カメラのプレビューをセットアップ
kotlin
cameraProviderFuture.get()でCameraProviderを取得し、Previewのインスタンスを作成して、surfaceProviderを設定します。val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(view.surfaceProvider)
}
カメラセレクターを設定し、ライフサイクルにバインド
kotlin
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, preview
)
} catch(exc: Exception) {
Log.e("CameraPreview", "Use case binding failed", exc)
}
デフォルトのバックカメラを使用するようにカメラセレクターを設定し、cameraProviderを使って、カメラのプレビューをライフサイクルオーナーにバインドします。これにより、アプリのライフサイクルと同期してカメラのリソースが管理されます。例外が発生した場合は、エラーログを出力します。
全体として、このコードはComposeを使用してカメラのプレビューを表示する一例ですが、実際のアプリではパーミッションの確認など、さらに多くの処理を行う必要があります。また、rememberが使用されているので、これらのインスタンスはComposableが再構築されても保持されます。
関連記事
アイデアノート > ネイティブアプリ開発