资讯动态

Android摄像头开发全攻略:API选型、核心实现与避坑指南

发布时间:2026/9/9 12:05:21 来源:尧图企业网站定制
简介面向Android开发者的摄像头功能完整工程资源覆盖从Camera1到Camera2 API的典型调用方式适合正在学习Android拍照、视频录制及自定义相机应用的初中级开发者。工程基于实际项目整理直接解决摄像头权限申请、预览画面旋转、多摄像头切换、闪光灯控制等常见难点。资源包共470个文件以java源码、xml布局与配置、class编译文件及png资源图片为主压缩包仅4.69MB便于快速导入Android Studio学习改造。已有6083人学习使用内容从基础预览到高级特性如YUV数据处理、人脸检测均有示例可帮助理解Android相机架构并避开常见坑点。无论以官方Camera2Basic入门还是参考第三方库思路都能获得可直接运行的参考实现。 做Android开发五年多摄像头这块的坑也算踩了个遍。手里攒下的代码和经验光相机回调那一堆状态机就能把人绕晕。今天这篇不是介绍什么黑科技而是把Android摄像头软件功能这件事完整拆开从最基础的预览、拍照、录像到对焦、变焦、闪光灯、人脸检测再到CameraX和Camera2怎么选、权限和生命周期怎么避坑以及模拟器虚拟摄像头、智能车摄像头这类特殊场景怎么接入。无论你是刚入门想给App加个扫码功能还是想折腾自己的智能硬件项目这篇都能提供一个可以直接落地的思路。1. Android摄像头功能全景一个摄像头到底能榨出多少功能从一个用户视角看摄像头功能就是打开相机、拍照、录像。但从开发者角度看Android摄像头软件功能可以拆成三层图像采集层、处理层和应用层。图像采集层负责从传感器拿到原始数据处理层负责格式转换、降噪、人脸框选、HDR合成应用层则是你看到的预览画面、拍照按钮、滤镜、美颜这些。做全功能实际上就是把这三层涉及的API都用到。Android官方对摄像头的支持经历了三代最早是Camera也被称为Camera1用android.hardware.Camera老项目里还在用Android 5.0开始引入Camera2用android.hardware.camera2包功能强大但API复杂回调一大堆再到2019年Google推出Jetpack CameraX基于Camera2封装用ViewModel那样的生命周期感知方式简化了开发。我的直观感受是Camera1就像是手动挡最早一手握方向盘一手挂挡能跑但挂错挡就熄火Camera2是专业单反的手动拨盘参数全但新手容易蒙CameraX则像是带辅助驾驶的自动挡把摄像头的常规能力封装成容易调用的接口同时保留了对Camera2特性的兼容。所以现在新项目我基本无脑选CameraX处理常规功能只有需要手动控制传感器级别参数时才去写Camera2的CameraCaptureSession。遇到特殊硬件比如热词里提到的树莓派OV5647模块、OV7670车牌识别这些在Android上往往要么走UVCCamera库要么走JNI封装与系统相机框架关系不大后面我会讲。1.1 手机摄像头不只是“拍照”很多人以为摄像头功能就是拍照录像其实一个完整的多媒体应用涉及的摄像头能力包括预览、静态拍照、视频录制、对焦自动/手动、变焦光学/数字、闪光灯控制开关、自动、手电筒、曝光补偿、白平衡、ISO、人脸检测、场景识别、RAW输出、HDR、连拍、延时摄影、慢动作。其中预览是所有功能的基础拍照和录像都是基于预览流做的。对焦、变焦、闪光灯是拍摄体验的关键如果这几个做不好App的用户体验会直线下降。另外摄像头并不能独立工作它要配合传感器方向、设备旋转角度、预览尺寸和相册图片的方向。很多新手会碰到拍出来的照片旋转90度就是没处理SensorOrientation。Android设备的摄像头传感器通常固定为90度或270度预览和拍照要分别做方向矫正。这个属于摄像头软件功能的隐藏必修课。我曾在某电商App上处理过商品拍摄模块看起来只有拍照但涉及正面/背面摄像头切换、二维码识别、光线太暗自动开闪光灯、低分辨率预览但高分辨率存储等需求所以哪怕是“拍照”这一个功能也要考虑场景上下文的适配。1.2 Camera、Camera2、CameraX三代API的演进逻辑Camera1的API简单open()然后setPreviewDisplay()就能预览但它是单线程同步模型很多操作必须按顺序来稍微复杂点的场景就卡顿。Camera2引入的CameraDevice、CaptureRequest、CaptureSession模型本质上是把一次拍照变成了“提交请求-队列执行-回调完成”的异步管道支持快速连拍、RAW输出、手动控制曝光和焦点但调试门槛直线上升。CameraX则是在Camera2之上做了一个官方兼容层内置生命周期感知自动处理旋转、缩放和摄像头切换例如我们想实现一个带拍照的基础相机用CameraX几十行代码就能跑通而用Camera2至少要写6个回调。如果你的项目要长期维护选CameraX能省掉不少心力。Google也给出了明确的演进态度Camera1在旧设备还有兼容性问题但官方已不在新版本更新它Camera2仍然维护CameraX是未来方向。所以我的建议是新项目一律CameraX老项目维护先用兼容层适配。CameraX还有一个好处是支持SetTargetRotation让我们不用自己算SensorOrientation这个坑很浅但很容易踩。2. 项目实战怎么选API和配置参数2.1 选CameraX还是Camera2我的决策公式这句话更像实际项目里的灵魂拷问。我的选择逻辑是如果业务里需要连续自动对焦、人脸追踪、实时滤镜而且产品要上线到几十款Android机型优先CameraX如果要做专业相机、实验室数据采集、需要控制每帧曝光时间或RAW拍摄用Camera2裸写。理由是CameraX内部封装了设备不兼容的适配逻辑比如不同厂商的性能模式、画面旋转、生命周期重启这些用Camera2自己处理会非常痛苦。我经历过一次录制视频在大法手机上黑屏、在蓝绿厂手机上掉帧的问题后来迁到CameraX后这些问题基本消失。具体决策公式化常规功能 快速迭代 CameraX深度控制 硬件闭环 Camera2两者也可以混合但不要混在一个页面上——比较推荐的方式是整个相机界面用CameraX需要特殊参数时通过Camera2CameraControl获取底层CameraDevice做定制。2.2 分辨率、帧率和画质参数怎么定很多同学喜欢直接写死1920x1080结果在低端机上卡成PPT。分辨率并不是越高越好要结合传感器输出能力、预览Surface类型、内存带宽和编码器。框架上CameraX的预览分析使用了ImageAnalysis这让我们能自定义分辨率但注意预览尺寸和拍照尺寸是两个维度预览尺寸取决于屏幕比例一般选和屏幕长宽比一致的拍照尺寸则选择传感器支持的最高或接近目标像素的尺寸通常4:3的12MP到48MP之间。帧率方面普通预览30fps够了如果做扫码或消除抖动可以看Sensor的fps范围。通过Camera2的SENSOR_INFO_ACTIVE_ARRAY_SIZE和SCALER_STREAMCONFIGURATION_MAP可以查支持的分辨率组合。CameraX选分辨率时可以用AspectRatio.RATIO_4_3或RATIO_16_9配合ResolutionSelector。开发时我一般先拿到CameraX内部支持的分辨率列表通过Camera2CameraInfo里拿StreamConfigurationMap再过滤出比例接近的实际尺寸。这样可以避免黑边。2.3 预览尺寸和拍照尺寸的适配预览Surface是TextureView或PreviewView它需要和屏幕的像素尺寸以及预览流尺寸对应。PhotoCapabilities里有个方法会返回预览尺寸范围。很多人以为把预览比例设成16:9就没问题但不同手机屏幕是19.5:9导致上下有黑边这是正常的最优雅的做法是让预览铺满屏幕、允许裁剪边缘因为用户注意力集中在中心裁掉一点无关紧要。拍照尺寸则要保持比例一致否则拍出来的照片旋转或拉伸。在CameraX里PreviewView会自动处理中心裁剪模式ScaleType.FILL_CENTER不需要你额外算啊算。3. 核心功能实现预览、拍照、录像、对焦和变焦一次打通3.1 预览CameraX的Preview和SurfaceProvider先做预览初始化。CameraX预览步骤创建ProcessCameraProvider绑定生命周期为Preview设置SurfaceProvider然后开启。代码大概是这样val preview Preview.Builder() .setTargetRotation(display.rotation) .build() preview.setSurfaceProvider(binding.previewView.surfaceProvider) cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview)这段代码背后做了很多事打开了相机设备、创建了Session、处理了旋转、还要和生命周期联动。所以如果你用Activity绑定到lifecycleOwner如果用Service就得手动管理。常见坑忘记bindToLifecycle或者重复bind会报“Camera is already bound”错误。避免方式是在每个Activity/Fragment的onCreate里只绑定一次onDestroy由lifecycle自动处理。3.2 拍照TakePicture的两种模式CameraX的ImageCapture有两种模式最小延迟模式CAPTURE_MODE_MINIMIZE_LATENCY和高质量模式CAPTURE_MODE_MAXIMIZE_QUALITY。前者适合连拍后者适合相机App的默认拍照因为按下快门后回显更快。拍照核心代码是bindToLifecycle时加入ImageCapture然后调用captureval imageCapture ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) .build() // 拍照 imageCapture.takePicture(ctx, executor, object : ImageCapture.OnImageSavedCallback { override fun onImageSaved(output: ImageCapture.OutputFileResults) { val uri output.savedUri // 这里拿到的是JPEG的Uri } override fun onError(exc: ImageCaptureException) { ... } })注意takePicture有两种重载一个直接保存到文件一个返回ImageProxy让我们能做旋转、水印、人脸框等后处理。如果要加水印或滤镜用ImageAnalyzer配ImageProxy处理但高频处理也会导致卡顿建议尺寸降一倍。3.3 录像VideoCapture与音视频合成录像可能是Android摄像里兼容性问题最多的点。CameraX当前的VideoCapture使用MediaRecorder或MediaCodec封装绑定方式一样val videoCapture VideoCapture.withOutput( VideoCapture.Output.FileOutputOptions.Builder(file) .build() ) val camera cameraProvider.bindToLifecycle(..., preview, imageCapture, videoCapture) // 开始录制 videoCapture.start(fileOutputOptions, executor, callback) // 停止 videoCapture.stop(callback)录出来的视频默认是MP4音频从麦克风采集。需要特别留意的坑切换摄像头、录制中熄屏、旋转屏幕都会导致录制中断或文件损坏。我自己遇到比较多的现象是三星设备上启动录像黑屏后来发现是预览尺寸和VideoCapture输出尺寸不匹配CameraX虽然会自动协调但还是要确保预览比例与目标视频比例一致。另一个坑是MediaRecorder的AudioSource不能用VOICE_CALL会报权限错误普通采音用CAMCORDER。3.4 对焦和变焦AF/AE模式的配置和缩放控制自动对焦是Camera2里的CONTROL_AF_MODECameraX里做了封装默认是Continuous。打开相机后如果你想实现点屏对焦可以用CameraControl.startFocusAndMeteringval focusMeteringAction FocusMeteringAction.Builder( MeteringPointFactory.fromPoint(previewView, x, y).createPoint(x, y) ).build() cameraControl.startFocusAndMetering(focusMeteringAction)这个会触发对焦并设置曝光区域。变焦更简单cameraControl.setLinearZoom(0.5f)0代表最广角1代表最大变焦。这里要特别注意一点单独用setZoomRatio可能在某些机型上不稳推荐用setLinearZoom它对焦距变化的映射统一了iOS的AVFoundation也是类似做法。另外闪光灯模式通过cameraControl.enableTorch(true)实现手电筒功能注意如果摄像头被其他App占用enableTorch会抛异常。4. 避坑实录从权限到生命周期那些文档里不写的坑4.1 权限与运行时授权为什么摄像头初始化总是失败Android 6.0以上需要动态申请CAMERA权限如果用户拒绝摄像头打开就报错。很多同学在onRequestPermissionsResult里忘记处理permanently denied勾选“不再询问”的情况。我总结的权限判断套路先检查ContextCompat.checkSelfPermission然后请求拒绝后再弹引导去设置页。另外如果你要录像并保存音频还需要RECORD_AUDIO权限两个权限要一起申请。如果只拍照不录音不要申请录音权限审核会卡。还有一个隐蔽坑同一时刻只能有一个应用绑定摄像头如果你用模拟器测试主机打开了摄像头模拟器里就会显示“正在使用摄像头”这个不是代码问题。4.2 生命周期绑定与释放旋转、后台导致的崩溃摄像头是独占资源onPause时如果还持有Session可能被系统强杀或黑屏。CameraX解决了这个问题但有个细节bindToLifecycle传入的LifecycleOwner必须在onDestroy前完成解绑。在Fragment里常用mLifecycleOwner严禁在onCreateView里用activity作为owner而Fragment被销毁却不解绑否则会出现“Camera is in use”或内部泄漏。实测中我还遇到过屏幕旋转时PreviewView重建导致surfaceProvider重新设置这时CameraX会认为你更新了Surface并自动重新配置但如果你在onDestroy中还调用cameraProvider.unbindAll()就会重新触发一次绑定流程产生闪烁。建议用withStateFlow或把相机页面固定为竖屏避免旋转折腾。4.3 Android Studio连接小米手机等真机调试问题摄像头开发必须上真机模拟器过于理想化。之前有人问Android Studio怎么连接小米手机这个流程其实不难先打开开发者选项点击“MIUI版本号”7次进入开发者选项打开“USB调试”再打开“USB安装”。然后电脑上装好ADB驱动手机连接后在Android Studio的设备列表能看到。常见问题小米手机默认把USB模式设成了“仅充电”要手动改成“文件传输”或“传送文件”还有一个是MIUI安全限制需要在手机端弹窗点允许USB调试。连接后可以用adb devices验证。真机调试摄像头还有个额外建议尽量准备2-3台不同系统的机器因为有些高版本API在不同机型行为差异很大尤其老的三星、华为以及最新Google Pixel。4.4 模拟器没有真实摄像头怎么办虚拟摄像头配置指南如果只是想快速验证界面逻辑Android模拟器支持模拟摄像头。配置方法是在AVD Manager里点编辑设备的摄像头选项将“Back”和“Front”改为“VirtualScene”或“Emulated”。用VirtualScene模式时模拟器会显示一个动态变化的3D场景适合验证预览和拍照流程。另外也可以用虚拟摄像头插件在Windows上装了虚拟摄像头驱动后Android Studio模拟器也能调用它作为输入源。不过虚拟摄像头没法模拟真实的光线、对焦、噪声所以只能用于UI/流程测试不能作为图像算法验证环境。5. 特殊场景扩展虚拟摄像头、树莓派与智能车5.1 用虚拟摄像头在模拟器里模拟各种摄像头在Android模拟器上选择“Emulated”摄像头时系统会提供一张棋盘格图片作为预览源适合测试相机调用的报文格式。热词里提到“安卓模拟器使用虚拟摄像头”其实这个做法在自动化测试时很实用不用真机也能跑UI测试。配置虚拟摄像头驱动后你甚至可以在电脑上播放一段MP4然后模拟器把它当成摄像头画面这样可以在CI环境里跑拍照用例。但需要注意虚拟摄像头的输出色彩空间和真实设备有差异AdobeRGB、YUV格式表现不同如果你的算法依赖色彩信息还是要用真实设备。5.2 树莓派OV5647的Android接入思路树莓派官方摄像头模块OV5647是CSI接口通常配合树莓派跑Linux系统但有人想在Android设备上接类似模块。其实有两种路线一是用UVC免驱摄像头通过USB接Android设备Android 5.0以上支持UVC应用层可用libyuv或UVCCamera库打开另一种是OV5647这种ISP数据输出需要在Android底层写Camera HAL模块不是普通App开发者能快速搞定的。除非你正在做系统开发否则建议放弃在Android上直接驱动CSI摄像头改成树莓派采集画面、通过RTSP推流Android端用MediaPlayer或者ExoPlayer拉流播放。这个方案我在智能车项目里用过稳定度远超直接在手机上改驱动。5.3 智能车摄像头搜线与补线的算法基础热搜词里还有“智能车摄像头搜线”“十字补线”这是全国大学生智能汽车竞赛里常见的图像处理任务。摄像头任务本质就是用二值化图像区分赛道边缘和背景然后通过行扫描找左右边界线的跳变点再通过最小二乘法拟合中心线。所谓“搜线”一般先从中间行开始向左右搜索遇到黑白跳变就是边界找到一组点后对边缘点做线性拟合。如果赛道出现十字左右边线会出现交叉这时候要用“补线”策略一般是根据历史数据预测丢失的线或者用最近几帧的边缘点做外推。这在Android端实现的话可以把摄像头图像转成Bitmap用OpenCV的Canny提取边缘再用概率霍夫变换找线段。跑在手机上性能会比较紧张所以通常把分辨率降一半再处理。最后分享两个我实际操作中的体会。第一做摄像头功能最重要的不是把API背熟而是要先想清楚你的目标帧率、分辨率、存储格式和业务场景比如扫码App就不应该用48M拍照低分辨率反而提升扫码速度。第二遇到摄像头黑屏或闪退优先检查权限和生命周期别一上来就怀疑算法。把CameraX的示例项目跑通再去改自己的业务代码效率会高很多。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价