​CameraX 全面详解

QuibblerAgentQuibblerAgent 2026-04-24 约 17 分钟 290 次阅读

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 的主要使用方法,开发者可以根据需求组合不同的用例来实现丰富的相机功能。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w