使用CameraX拍摄照片后如何实现最新照片预览(类Messenger等流程)
CameraX 拍摄后预览确认再保存的实现方案
核心交互逻辑
完全对齐WhatsApp、Messenger类应用的相机流程:拍摄动作触发后不直接写文件持久化,先把内存中的拍摄结果加载到预览页,由用户选择重拍或者确认保存,再执行后续的文件写入操作。整体流程拆分为三个环节:
- 拍摄完成后从CameraX回调中获取原始图片Bitmap,处理好旋转适配
- 跳转至全屏确认预览页,展示刚拍摄的原图,提供「重拍」「确认保存」两个操作入口
- 触发确认逻辑后,再执行水印添加、文件存储、媒体库同步等落盘操作;选择重拍则直接关闭预览页回到取景界面,丢弃临时存在内存中的图片数据。
现有代码的具体调整步骤
1. 修改拍摄输出模式
将当前拍摄完成直接存文件的逻辑替换为内存获取模式,避免拍完立刻写盘:
- 替换原
takePhoto()中构建OutputFileOptions直接存盘的逻辑,改用OnImageCapturedCallback直接获取内存中的图片数据:
private fun takePhoto() { imageCapture?.takePicture( ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageCapturedCallback() { override fun onCaptureSuccess(image: ImageProxy) { // 完成图片旋转适配得到可用Bitmap val capturedBitmap = adaptImageProxyRotation(image) image.close() // 跳转预览页,传递当前Bitmap val intent = Intent(this@MainActivity, PhotoConfirmActivity::class.java) // 超大型Bitmap需先压缩,避免Intent传输大小超限 intent.putExtra("captured_bitmap", capturedBitmap) startActivity(intent) } override fun onError(exception: ImageCaptureException) { Toast.makeText(this@MainActivity, "拍摄失败:${exception.message}", Toast.LENGTH_SHORT).show() } } ) }
- 补充图片旋转适配方法,解决拍摄图片方向错乱问题:
private fun adaptImageProxyRotation(image: ImageProxy): Bitmap { val rotationMatrix = Matrix().apply { postRotate(image.imageInfo.rotationDegrees.toFloat()) // 前置摄像头拍摄时可按需添加镜像翻转逻辑 } val rawBitmap = image.toBitmap() return Bitmap.createBitmap( rawBitmap, 0, 0, rawBitmap.width, rawBitmap.height, rotationMatrix, true ) }
2. 搭建确认预览页
- 新建
PhotoConfirmActivity,对应布局实现全屏展示ImageView作为图片显示层,底部并列放置两个操作按钮:左侧为「重拍」按钮,右侧为「确认保存」按钮 - 页面启动时从Intent中取出传入的Bitmap,加载到ImageView上展示
3. 拆分操作逻辑
- 重拍逻辑:直接调用
finish()关闭预览页,回到主界面的相机取景状态,不需要做任何文件操作,内存中的临时Bitmap会被系统自动回收 - 确认保存逻辑:调用已经实现好的
addWatermark()方法给Bitmap添加水印,再按照原有getOutputDirectory()的路径将处理后的Bitmap写入为JPG文件,最后同步更新系统媒体库完成持久化存储。
可顺手优化的现有问题
- 替换当前使用的alpha版本CameraX依赖为稳定正式版,降低API兼容风险
- 移除
MANAGE_EXTERNAL_STORAGE权限,当前使用的externalMediaDirs属于应用专属外部目录,不需要申请全文件访问权限,可大幅降低应用上架审核被拒的概率 - 给拍照按钮增加防重复点击逻辑,避免用户短时间连续点击触发多次拍摄,产生冗余的临时图片
内容的提问来源于stack exchange,提问作者Georgi Tasev
相关产品推荐
相关产品推荐

