1. 项目概述:Android拍照录像应用开发
这个基于Android Studio和Java语言的拍照录像软件源代码,是一个完整的移动端多媒体采集解决方案。作为一名有多年Android开发经验的工程师,我经常遇到需要快速实现基础拍照录像功能的需求场景。这个项目代码结构清晰,封装了Camera2 API的核心功能,适合作为二次开发的基础框架或学习Camera开发的参考案例。
项目采用标准的MVC架构,将相机预览、拍照控制、视频录制等功能模块化。核心优势在于对Android不同版本相机API的兼容处理,以及针对常见设备差异性的适配方案。我在实际开发中发现,很多团队在实现这类功能时容易忽略内存管理和线程调度的优化,而这个项目在这些细节上处理得相当到位。
2. 开发环境准备
2.1 Android Studio配置要点
建议使用最新稳定版的Android Studio(当前为Giraffe版本),配置时需要注意几个关键点:
- Gradle版本兼容性:在gradle-wrapper.properties中指定7.4以上的Gradle版本
- NDK配置:如果涉及原生代码处理,需要安装对应版本的NDK
- Java环境:项目使用Java 17特性,需确保IDE和Gradle都配置了正确的JDK版本
常见问题:如果遇到"源发行版17需要目标发行版17"的警告,检查以下配置:
- File → Project Structure → SDK Location中的JDK路径
- build.gradle中的compileOptions配置
2.2 权限与设备兼容性处理
在AndroidManifest.xml中需要声明以下权限:
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>对于Android 6.0+设备,必须实现运行时权限申请。我封装了一个通用的权限检查工具类:
public class PermissionUtil { public static boolean checkAndRequest(Activity activity, String[] permissions) { List<String> denied = new ArrayList<>(); for (String perm : permissions) { if (ContextCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) { denied.add(perm); } } if (!denied.isEmpty()) { ActivityCompat.requestPermissions(activity, denied.toArray(new String[0]), REQUEST_CODE); return false; } return true; } }3. 相机功能实现详解
3.1 Camera2 API核心架构
项目采用Camera2 API而非已废弃的Camera API,主要架构包括:
- CameraManager - 设备相机系统服务入口
- CameraCharacteristics - 相机特性查询
- CameraDevice - 具体的相机设备
- CameraCaptureSession - 捕获会话管理
- CaptureRequest - 捕获请求构建
初始化相机的典型流程:
// 1. 获取CameraManager CameraManager manager = (CameraManager) context.getSystemService(CAMERA_SERVICE); // 2. 遍历可用相机 for (String cameraId : manager.getCameraIdList()) { CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) { this.cameraId = cameraId; break; } } // 3. 打开相机 manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { this.cameraDevice = camera; createCaptureSession(); } // ...其他回调方法 }, backgroundHandler);3.2 预览画面实现
预览画面通过TextureView实现,关键步骤:
- 设置TextureView的SurfaceTextureListener
- 在onSurfaceTextureAvailable回调中配置相机预览
- 创建CaptureRequest.Builder设置预览目标Surface
优化点:
- 根据设备支持的分辨率选择最佳预览尺寸
- 处理屏幕旋转时的方向适配
- 考虑不同屏幕宽高比的适配问题
我常用的分辨率选择算法:
private Size chooseOptimalSize(Size[] choices, int width, int height) { List<Size> bigEnough = new ArrayList<>(); for (Size option : choices) { if (option.getWidth() >= width && option.getHeight() >= height) { bigEnough.add(option); } } if (bigEnough.isEmpty()) { return choices[choices.length - 1]; // 返回最大可用尺寸 } return Collections.min(bigEnough, new CompareSizesByArea()); }4. 多媒体捕获功能实现
4.1 拍照功能实现
拍照流程的核心代码:
private void takePicture() { try { final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(imageReader.getSurface()); captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 设置方向 int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation)); // 执行拍照 captureSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(...) { // 保存照片 } }, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }4.2 视频录制实现
视频录制需要处理音频和视频的同步采集,主要步骤:
- 配置MediaRecorder:
private void prepareRecorder() { mediaRecorder = new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setOutputFile(createVideoFile().getAbsolutePath()); mediaRecorder.setVideoEncodingBitRate(10000000); mediaRecorder.setVideoFrameRate(30); mediaRecorder.setVideoSize(videoSize.getWidth(), videoSize.getHeight()); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mediaRecorder.setOrientationHint(rotation); mediaRecorder.prepare(); }- 在录制过程中处理相机预览和视频采集的Surface切换
5. 性能优化与问题排查
5.1 内存管理最佳实践
相机应用常见的内存问题及解决方案:
- Bitmap内存泄漏:
- 使用BitmapFactory.Options.inSampleSize进行图片压缩
- 及时回收不再使用的Bitmap对象
- Surface泄漏:
- 确保在Activity/Fragment生命周期结束时释放所有Surface
- 实现正确的TextureView.SurfaceTextureListener
- 相机资源释放:
@Override protected void onStop() { super.onStop(); if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } if (mediaRecorder != null) { mediaRecorder.release(); mediaRecorder = null; } }5.2 常见问题排查指南
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 预览画面黑屏 | Surface未正确配置 | 检查TextureView状态和相机预览Surface设置 |
| 拍照延迟高 | 自动对焦模式设置不当 | 使用CONTROL_AF_MODE_CONTINUOUS_PICTURE |
| 视频录制失败 | 权限不足或存储空间不够 | 检查权限和存储状态,测试不同分辨率 |
| 相机启动崩溃 | 相机被其他应用占用 | 实现相机可用性检查,优雅降级处理 |
我在实际项目中总结的几个调试技巧:
- 使用CameraCharacteristics获取设备支持的全部参数
- 为CameraDevice.StateCallback实现完整的错误处理
- 在不同厂商设备上测试关键功能
6. 功能扩展建议
基于这个基础框架,可以进一步实现:
- 高级拍摄模式:
- 手动对焦/曝光控制
- HDR模式
- 连拍模式
- 实时滤镜处理:
// 使用OpenGL ES实现实时滤镜 public class CameraGLRenderer implements GLSurfaceView.Renderer { @Override public void onDrawFrame(GL10 gl) { // 应用滤镜效果 filter.apply(); // 绘制相机预览帧 texture.draw(); } }- 云端同步功能:
- 集成Firebase Storage自动备份
- 实现拍摄内容分类管理
这个项目代码结构清晰,各功能模块解耦良好,非常适合作为基础进行二次开发。我在实际使用中发现,将相机控制逻辑封装成独立的CameraController类,可以大大提高代码的可维护性和复用性。