在使用Jetpack Compose开发安卓应用,当在学习使用CameraX组件时发现官方提供的教程不是Compose的。教程地址如下:
https://developer.android.com/codelabs/camerax-getting-started?hl=zh-cn#1
与是我就记录一下,简单的示例。
内容参考:
https://medium.com/@deepugeorge2007travel/mastering-camerax-in-jetpack-compose-a-comprehensive-guide-for-android-developers-92ec3591a189
依赖
build.gradle中增加以下内容:
dependencies {// Camerax implementationdef cameraxVersion = "1.3.1"implementation ("androidx.camera:camera-core:${cameraxVersion}")implementation ("androidx.camera:camera-camera2:${cameraxVersion}")implementation ("androidx.camera:camera-view:${cameraxVersion}")implementation ("androidx.camera:camera-lifecycle:$cameraxVersion")// Camerax implementation
}
权限
修改文件CmrXTutorial/app/src/main/AndroidManifest.xml
增加以下内容:
<uses-featureandroid:name="android.hardware.camera"android:required="false" />
<uses-permission android:name="android.permission.CAMERA"/>
修改完以后形如:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-featureandroid:name="android.hardware.camera"android:required="false" /><uses-permission android:name="android.permission.CAMERA"/><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"...略...</application>
</manifest>
cmrxtutorial/composables/Camerax.kt
代码如下:
package com.android.example.cmrxtutorial.composablesimport android.content.ContentValues
import android.content.Context
import android.os.Build
import android.provider.MediaStore
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine@Composable
fun CameraPreviewScreen() {val lensFacing = CameraSelector.LENS_FACING_BACKval lifecycleOwner = LocalLifecycleOwner.currentval context = LocalContext.currentval preview = Preview.Builder().build()val previewView = remember {PreviewView(context)}val cameraxSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()val imageCapture = remember {ImageCapture.Builder().build()}LaunchedEffect(lensFacing) {val cameraProvider = context.getCameraProvider()cameraProvider.unbindAll()cameraProvider.bindToLifecycle(lifecycleOwner, cameraxSelector, preview, imageCapture)preview.setSurfaceProvider(previewView.surfaceProvider)}Box(contentAlignment = Alignment.BottomCenter, modifier = Modifier.fillMaxSize()) {AndroidView({ previewView }, modifier = Modifier.fillMaxSize())Button(onClick = { captureImage(imageCapture, context) }) {Text(text = "Capture Image")}}
}private fun captureImage(imageCapture: ImageCapture, context: Context) {val name = "CameraxImage.jpeg"val contentValues = ContentValues().apply {put(MediaStore.MediaColumns.DISPLAY_NAME, name)put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")}}val outputOptions = ImageCapture.OutputFileOptions.Builder(context.contentResolver,MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues).build()imageCapture.takePicture(outputOptions,ContextCompat.getMainExecutor(context),object : ImageCapture.OnImageSavedCallback {override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {println("Successs")}override fun onError(exception: ImageCaptureException) {println("Failed $exception")}})
}private suspend fun Context.getCameraProvider(): ProcessCameraProvider =suspendCoroutine { continuation ->ProcessCameraProvider.getInstance(this).also { cameraProvider ->cameraProvider.addListener({continuation.resume(cameraProvider.get())}, ContextCompat.getMainExecutor(this))}}
cmrxtutorial/MainActivity.kt
代码如下:
package com.android.example.cmrxtutorialimport android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import com.android.example.cmrxtutorial.composables.CameraPreviewScreen
import com.android.example.cmrxtutorial.ui.theme.CmrXTutorialThemeclass MainActivity : ComponentActivity() {private val cameraPermissionRequest =registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->if (isGranted) {setCameraPreview()} else {// Camera permission denied}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)when (PackageManager.PERMISSION_GRANTED) {ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA) -> {setCameraPreview()}else -> {cameraPermissionRequest.launch(Manifest.permission.CAMERA)}}}private fun setCameraPreview() {setContent {CmrXTutorialTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {CameraPreviewScreen()}}}}
}