CameraX 全面详解
CameraX 是 Jetpack 组件之一,旨在简化相机应用的开发流程,同时解决不同厂商设备的兼容性问题。下面我将从基础到高级详细介绍如何使用 CameraX。
1、核心概念
1.1、Use Cases
CameraX 围绕三个主要用例构建:
Preview: 预览画面显示
Image Analysis: 图像分析
Image Capture: 拍摄照片
1.2、Lifecycle 集成
CameraX 会自动管理相机的生命周期,与 Activity/Fragment 的生命周期绑定。
2、基本实现步骤
2.1、添加依赖项
首先在 build.gradle 中添加依赖:
def camerax_version = "1.3.0-alpha04"
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"2.2、权限声明
在 AndroidManifest.xml 中添加必要权限:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" />2.3、创建 PreviewView
在布局文件中添加 PreviewView:
<androidx.camera.view.PreviewView
android:id="@+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>2.4、初始化 CameraProvider
class MainActivity : AppCompatActivity() {
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
if (!hasPermissions()) {
requestPermission()
} else {
startCamera()
}
}
private fun hasPermissions(): Boolean {
return ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
}
private fun requestPermission() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CODE_PERMISSIONS
)
}
@SuppressLint("UnsafeOptInUsageError")
private fun startCamera() {
val previewView = findViewById<PreviewView>(R.id.preview_view)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
// 创建预览用例
val preview = Preview.Builder().build()
// 将预览连接到视图
preview.setSurfaceProvider(previewView.surfaceProvider)
try {
// 解除之前的所有绑定
cameraProvider.unbindAll()
// 绑定用例到生命周期
cameraProvider.bindToLifecycle(
this,
CameraSelector.DEFAULT_BACK_CAMERA,
preview
)
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
}3、扩展功能实现
3.1、拍照功能
private fun setupCaptureButton(cameraProvider: ProcessCameraProvider) {
val captureBtn = findViewById<Button>(R.id.btn_capture)
captureBtn.setOnClickListener {
takePhoto(cameraProvider)
}
}
@SuppressLint("UnsafeOptInUsageError")
private fun takePhoto(cameraProvider: ProcessCameraProvider) {
// 创建 ImageCapture 用例
val imageCapture = ImageCapture.Builder()
.setTargetRotation(windowManager.defaultDisplay.rotation)
.build()
// 重新绑定用例
cameraProvider.bindToLifecycle(
this,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
imageCapture
)
// 准备保存的文件
val outputFile = File(filesDir, "${System.currentTimeMillis()}.jpg")
// 创建输出选项
val outputOptions = ImageCapture.OutputFileOptions.Builder(outputFile).build()
// 执行拍照
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Toast.makeText(this@MainActivity,
"照片已保存: ${outputFile.savedUri ?: outputFile.file}",
Toast.LENGTH_SHORT).show()
}
override fun onError(exception: ImageCaptureException) {
Log.e(TAG, "拍照失败: ", exception)
}
})
}3.2、图像分析
private fun setupAnalysis(cameraProvider: ProcessCameraProvider) {
val analyzerThreadHandler = Handler(Looper.getMainLooper())
val analysisUseCase = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.also {
it.setAnalyzer(ContextCompat.getMainExecutor(this)) { imageProxy ->
// 在这里处理每一帧图像
analyzeFrame(imageProxy)
imageProxy.close()
}
}
cameraProvider.bindToLifecycle(
this,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
analysisUseCase
)
}
private fun analyzeFrame(image: ImageProxy) {
// 获取图像的平面数组(YUV格式)
val planes = image.planes
// Y分量(亮度)
val yBuffer = planes[0].buffer
val uBuffer = planes[1].buffer
val vBuffer = planes[2].buffer
// 这里可以进行各种图像处理...
}4、进阶主题
4.1、摄像头切换
fun switchCamera(isFront: Boolean) {
val newCameraSelector = if (isFront) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
cameraProvider?.unbindAll()
bindUseCases(newCameraSelector)
}4.2、分辨率设置
val resolution = Size(width, height)
val preview = Preview.Builder()
.setTargetResolution(resolution)
.build()
val imageCapture = ImageCapture.Builder()
.setTargetResolution(resolution)
.build()4.3、缩放和手势控制
previewView.setOnTouchListener { _, event ->
when(event.actionMasked) {
MotionEvent.ACTION_POINTER_DOWN -> {
initialFingerSpacing = calculateDistanceBetweenFingers(event)
}
MotionEvent.ACTION_MOVE -> {
currentFingerSpacing = calculateDistanceBetweenFingers(event)
handleZoom(currentFingerSpacing / initialFingerSpacing)
}
}
true
}
private fun handleZoom(delta: Float) {
cameraControl?.let { control ->
val currentRatio = control.zoomState.value?.zoomRatio ?: 1f
control.setZoomRatio(currentRatio * delta.coerceIn(MIN_ZOOM..MAX_ZOOM))
}
}5、注意事项
线程安全: 图像分析应在后台线程执行
资源释放: 及时关闭 ImageProxy 对象
异常处理: 妥善处理可能的相机不可用情况
API级别: 最低支持 API Level 21
内存管理: 大尺寸图像会消耗大量内存
6、最新改进(CameraX 1.3+)
视频录制支持
HDR 和高分辨率模式
更好的低光表现
增强的设备兼容性
以上就是 CameraX 的主要使用方法,开发者可以根据需求组合不同的用例来实现丰富的相机功能。

