一、基础概述
1. 是什么
CameraX 是 Google Jetpack 官方推出的相机封装库 ,底层基于 Camera2 API 深度封装,彻底淘汰老旧 Camera1、简化复杂 Camera2 ,是目前 Android 开发唯一官方推荐的相机方案。
2. 核心优势(为什么不用 Camera1/Camera2)
- API 极简:告别 Camera2 几十行复杂配置、繁琐回调、状态管理
- 生命周期自动管理 :绑定 Lifecycle,页面销毁自动释放相机,无内存泄漏
- 全版本兼容 :最低兼容 Android 5.0(API 21) ,覆盖 99% 机型
- 适配性极强:自动兼容异形屏、刘海、不同厂商相机适配、比例自动矫正
- 内置四大能力:预览、拍照、图像分析、视频录制一站式搞定
- 线程内部自动管理,无需手动处理子线程、释放资源
- 完美兼容 View 体系 + Compose,支持 Viewfinder
3. 版本与依赖(2026 最新稳定版,直接复制)
最新稳定版:1.5.0 (适配 AGP 8+、Compose、全系统版本)Module 级 build.gradle.kts
kotlin
kotlin
// CameraX 全套依赖(全部引入,按需使用)
val cameraXVersion = "1.5.0"
implementation("androidx.camera:camera-core:$cameraXVersion")
implementation("androidx.camera:camera-camera2:$cameraXVersion")
implementation("androidx.camera:camera-lifecycle:$cameraXVersion")
implementation("androidx.camera:camera-view:$cameraXVersion") // PreviewView 视图
implementation("androidx.camera:camera-video:$cameraXVersion") // 视频录制专属
4. 权限清单配置(必须)
AndroidManifest.xml
xml
xml
<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 录像需要麦克风权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 保存图片/视频到本地存储(Android 13+ 适配) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<!-- 声明应用需要相机硬件 -->
<uses-feature
android:name="android.hardware.camera.any"
android:required="true" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
二、核心概念(先懂概念再写代码,不懵)
1. 四大核心 UseCase(所有能力基于这 4 个)
CameraX 所有功能都以 ** 用例(UseCase)** 为单位构建,可自由组合、绑定生命周期:
- Preview(预览) :画面显示到屏幕,必备基础
- ImageCapture(拍照) :拍摄图片、保存本地
- ImageAnalysis(图像分析) :帧数据分析、二维码扫描、人脸识别、AI 帧处理
- VideoCapture(视频录制) :高清视频录制、音频同步
2. 核心类全解
- ProcessCameraProvider:相机全局管理者,单例,绑定用例、解绑、管理相机生命周期
- CameraSelector :选择前置 / 后置摄像头
- PreviewView:官方预览控件,替代 TextureView/SurfaceView,自动适配比例、拉伸矫正
- Camera:绑定后返回的相机实例,可控制闪光灯、缩放、对焦
- Executor:内部异步线程,无需自己创建线程池
3. 整体流程(固定公式,所有代码通用)
plaintext
markdown
1. 申请相机权限
2. 获取 ProcessCameraProvider 单例
3. 构建各类 UseCase(预览/拍照/分析/录像)
4. 选择摄像头(前置/后置)
5. bindToLifecycle 绑定生命周期(自动管理释放)
6. 调用对应能力(拍照/录像/分析)
三、原生 View 完整实战代码(Kotlin,Activity 版,最基础完整版)
包含:权限申请(Activity Result API)+ 预览 + 拍照 + 保存相册 + 切换前后置 + 闪光灯,直接复制可用。
1. XML 布局(activity_main.xml)
xml
xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- CameraX 官方预览控件 -->
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 拍照按钮 -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnTakePhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="50dp"
android:src="@drawable/ic_camera_shutter" />
</LinearLayout>
</layout>
2. Activity 完整代码(含权限、全部功能)
kotlin
kotlin
import android.Manifest
import android.content.ContentValues
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.Camera
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.core.content.ContextCompat
import com.google.common.util.concurrent.ListenableFuture
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
// 预览控件
private lateinit var previewView: PreviewView
// 拍照用例
private var imageCapture: ImageCapture? = null
// 相机实例
private var camera: Camera? = null
// 后台线程池(CameraX 内部回调专用)
private lateinit var cameraExecutor: ExecutorService
// ========== 权限:Activity Result API 申请 ==========
private val requestCameraPermission = registerForActivityResult(
androidx.activity.result.contract.ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// 权限通过,启动相机
startCamera()
} else {
Toast.makeText(this, "需要相机权限", Toast.LENGTH_SHORT).show()
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
previewView = findViewById(R.id.previewView)
val btnTakePhoto = findViewById<com.google.android.material.floatingactionbutton.FloatingActionButton>(R.id.btnTakePhoto)
// 初始化线程池
cameraExecutor = Executors.newSingleThreadExecutor()
// 权限判断
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== android.content.pm.PackageManager.PERMISSION_GRANTED
) {
startCamera()
} else {
// 申请权限
requestCameraPermission.launch(Manifest.permission.CAMERA)
}
// 拍照点击事件
btnTakePhoto.setOnClickListener {
takePhoto()
}
}
// ========== 1. 启动相机核心方法 ==========
private fun startCamera() {
val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> =
ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
// 获取相机管理者单例
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// 1. 构建预览用例
val preview = Preview.Builder()
.build()
.apply {
// 绑定预览视图
setSurfaceProvider(previewView.surfaceProvider)
}
// 2. 构建拍照用例
imageCapture = ImageCapture.Builder()
// 优先低延迟拍照
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
// 3. 选择摄像头:后置摄像头(CameraSelector.DEFAULT_FRONT_CAMERA 前置)
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
// 解绑旧的绑定(防止重复绑定报错)
cameraProvider.unbindAll()
// 4. 绑定生命周期 + 所有用例(核心!自动生命周期管理)
camera = cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageCapture
)
}, ContextCompat.getMainExecutor(this))
}
// ========== 2. 拍照 + 保存到系统相册 ==========
private fun takePhoto() {
val imageCapture = imageCapture ?: return
// 图片命名
val name = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
// Android 10+ 分区存储适配
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
// 输出保存选项
val outputOptions = ImageCapture.OutputFileOptions
.Builder(contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
.build()
// 执行拍照
imageCapture.takePicture(
outputOptions,
cameraExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Toast.makeText(this@MainActivity, "拍照成功", Toast.LENGTH_SHORT).show()
}
override fun onError(exception: ImageCaptureException) {
Toast.makeText(this@MainActivity, "拍照失败:${exception.message}", Toast.LENGTH_SHORT).show()
}
}
)
}
// ========== 页面销毁,释放线程 ==========
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
}
四、扩展常用功能(高频补充)
1. 切换前后置摄像头
kotlin
kotlin
// 拿到当前camera实例,切换镜头
val isBack = camera?.cameraInfo?.lensFacing == CameraSelector.LENS_FACING_BACK
val newSelector = if (isBack) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
// 重新绑定
cameraProvider.unbindAll()
camera = cameraProvider.bindToLifecycle(this, newSelector, preview, imageCapture)
2. 闪光灯控制(开启 / 关闭 / 自动)
kotlin
arduino
// 开启闪光灯
camera?.cameraControl?.enableTorch(true)
// 关闭闪光灯
camera?.cameraControl?.enableTorch(false)
3. ImageAnalysis 图像帧分析(二维码扫描专用)
实时获取相机每一帧数据,不影响预览、不影响拍照,用于扫码、人脸、图像识别
kotlin
scss
// 构建分析用例
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) // 只保留最新帧
.build()
// 帧数据回调
imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy ->
// 每一帧 ImageProxy 数据,做扫码/分析
// 用完必须关闭!否则相机卡死
imageProxy.close()
}
// 绑定的时候加入用例
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalysis)
4. VideoCapture 视频录制(完整基础)
kotlin
scss
// 构建视频录制器
val recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(Quality.HD)) // 画质
.build()
val videoCapture = VideoCapture.withOutput(recorder)
// 开始录制
val recording = videoCapture.output
.prepareRecording(this, contentValues)
.withAudioEnabled() // 开启音频
.start(ContextCompat.getMainExecutor(this)) {}
// 停止录制
recording.stop()
五、Compose 中 CameraX 使用(Viewfinder 官方组件)
Compose 无原生预览控件,CameraX 官方提供 CameraViewfinder ,结合协程、生命周期,纯 Compose 写法,搭配你之前学的 Accompanist 权限 完美使用。
kotlin
kotlin
import androidx.camera.compose.CameraViewfinder
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import kotlinx.coroutines.launch
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import com.google.accompanist.permissions.rememberPermissionState
import android.Manifest
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun ComposeCameraXPage() {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val scope = rememberCoroutineScope()
// Accompanist 权限
val cameraPermission = rememberPermissionState(Manifest.permission.CAMERA)
var surfaceRequest by remember { mutableStateOf<SurfaceRequest?>(null) }
LaunchedEffect(cameraPermission.status.isGranted) {
if (cameraPermission.status.isGranted) {
// 获取相机提供者
val provider = ProcessCameraProvider.awaitInstance(context)
// 预览
val preview = Preview.Builder().build().apply {
setSurfaceProvider { surfaceRequest = it }
}
// 拍照用例
val imageCapture = ImageCapture.Builder().build()
// 后置摄像头
val selector = CameraSelector.DEFAULT_BACK_CAMERA
provider.unbindAll()
provider.bindToLifecycle(
lifecycleOwner, selector, preview, imageCapture
)
}
}
Column(modifier = Modifier.fillMaxSize()) {
if (cameraPermission.status.isGranted && surfaceRequest != null) {
// Compose 官方相机预览
CameraViewfinder(
surfaceRequest = surfaceRequest!!,
modifier = Modifier.fillMaxSize()
)
} else {
Button(onClick = { cameraPermission.launchRequest() }) {
Text("申请相机权限")
}
}
}
}
六、Camera1 / Camera2 / CameraX 全方位对比(面试必背)
表格
| 对比项 | Camera1 | Camera2 | CameraX |
|---|---|---|---|
| 发布版本 | Android 5.0 以前 | Android 5.0+ (API21) | Jetpack 封装,API21 全兼容 |
| API 难度 | 简单但坑极多、适配差 | API 极繁琐、配置复杂、状态难管理 | API 极简、开箱即用 |
| 生命周期管理 | 无,需手动释放,极易内存泄漏 | 无,手动管理 | 绑定 Lifecycle,自动释放 |
| 机型适配 | 兼容性极差,厂商适配乱 | 适配一般,细节坑多 | 自动全机型适配、比例矫正 |
| 功能 | 基础预览拍照 | 功能最全、底层全部能力 | 封装全部常用能力,够用且简单 |
| 开发代码量 | 中等 | 极多(上百行配置) | 极少(固定模板) |
| 官方现状 | 完全废弃 | 底层 API,不建议应用层直接开发 | 官方唯一推荐、持续维护 |
| 底层 | 原生旧相机框架 | 原生新一代相机框架 | 底层基于 Camera2 封装 |
七、高频踩坑大全(避坑必看)
- 预览画面拉伸、变形 用官方
PreviewView,不要自己用 SurfaceView/TextureView,内部自动做比例矫正。 - 重复绑定崩溃 每次启动相机前必须调用
cameraProvider.unbindAll()全部解绑,再重新绑定。 - ImageAnalysis 分析后相机卡死 每一帧回调的
ImageProxy必须调用 .close () 关闭,否则帧堆积堵塞。 - Android 10+ 图片保存找不到 严格用分区存储
MediaStore保存,不要直接操作文件路径,上面代码已完美适配。 - 权限申请时机 必须先权限、后启动相机;绑定用例必须在主线程回调内执行。
- 页面销毁相机未释放 依靠
bindToLifecycle自动释放,无需手动释放相机;仅需关闭自定义线程池。 - 前后置切换报错 切换前必须
unbindAll()全部解绑,再重新绑定新摄像头 + 所有用例。
八、面试满分速记版
- CameraX 是什么:Jetpack 官方相机库,底层封装 Camera2,全版本兼容、生命周期安全、API 极简,替代老旧 Camera1/Camera2。
- 四大用例 :
Preview预览、ImageCapture拍照、ImageAnalysis帧分析、VideoCapture视频录制。 - 核心流程 :权限申请 → 获取
ProcessCameraProvider→ 构建 UseCase → 选择镜头 →bindToLifecycle绑定生命周期。 - 最大优势 :生命周期自动管理无内存泄漏、全机型适配、API 简单、内置完整能力。
- 和 Camera2 区别:Camera2 是底层复杂原生 API,CameraX 是上层友好封装,屏蔽底层繁琐细节。
九、项目最终总结论
- 日常开发所有相机需求全部用 CameraX,不要再碰 Camera1、原生 Camera2。
- View 体系用
PreviewView,Compose 用CameraViewfinder+ Accompanist 权限。 - 用例自由组合:只预览、预览 + 拍照、预览 + 分析、预览 + 录像按需绑定。
- 代码全部固定模板,复制修改即可快速开发相机、扫码、拍照项目。
十、分业务最终要不要引入三方(直接照做)
- 单纯拍照 :0 三方,纯 CameraX 原生足够
- 扫码功能 :CameraX + ZXing(仅解码)
- 头像裁剪 :CameraX 拍照 + uCrop(仅裁剪)
- 美颜 / 滤镜:CameraX + 美颜渲染库
- 人脸:CameraX + ML Kit
- 普通视频录制:纯 CameraX 原生足够
- 短视频剪辑:CameraX 录像 + Media3 播放处理