Android Camera2 API拍照按钮显示时机及卡死问题排查
我来帮你梳理下这个Camera2 API按钮状态控制的坑,结合你用到的android-Camera2Basic示例代码,咱们一步步拆解问题和解决方案:
先分析你遇到的两个核心问题
1. 快速点击按钮后消失不显示
你最初在lockFocus()里隐藏按钮、unlockFocus()里显示的逻辑,多数情况有效但扛不住快速点击——本质是Camera2的状态机是异步执行的,快速点击会多次触发lockFocus(),导致相机状态混乱,后续的unlockFocus()可能因为状态冲突没有被正确执行,按钮就一直处于隐藏状态。
2. 改在onCaptureSequenceCompleted显示按钮后,相机卡在AE状态
当你把按钮显示逻辑移到onCaptureSequenceCompleted,虽然按钮能出来,但此时相机的AE(自动曝光)状态可能还没从拍照的过渡状态回到稳定预览状态。用户点击按钮触发拍照时,代码里的AE状态判断条件不满足,就会无限卡在STATE_WAITING_PRECAPTURE或STATE_WAITING_NON_PRECAPTURE,无法进入STATE_PICTURE_TAKEN执行拍照。
正确的按钮显示时机方案
1. 初始显示按钮的时机:相机进入稳定预览状态
按钮默认设为GONE,等相机完全就绪、预览流稳定运行后再显示。在Camera2Basic的状态机中,当mState切换到STATE_PREVIEW时,就代表相机已经进入正常预览状态,此时可以安全显示拍照按钮:
case STATE_PREVIEW: { // 相机就绪,显示拍照按钮 takePicture.setVisibility(View.VISIBLE); break; }
2. 拍照完成/失败后恢复按钮的时机:相机回到稳定预览状态
不能只依赖unlockFocus()或onCaptureSequenceCompleted,必须等相机完全回到STATE_PREVIEW状态,同时配合防抖标记避免重复点击:
- 第一步:给按钮加防抖标记,防止快速点击打乱状态机
private boolean isCapturing = false; takePicture.setOnClickListener(v -> { if (!isCapturing) { isCapturing = true; takePicture.setVisibility(View.GONE); // 点击后立即隐藏 lockFocus(); // 启动拍照流程 } }); - 第二步:在相机回到
STATE_PREVIEW时,恢复按钮状态
在onCaptureResultReceived的状态处理中,当mState切换回STATE_PREVIEW时,重置防抖标记并显示按钮:case STATE_PREVIEW: { takePicture.setVisibility(View.VISIBLE); isCapturing = false; // 重置拍照标记 break; } - 第三步:确保拍照失败时也能回到预览状态
在onCaptureFailed回调中,主动调用unlockFocus()让相机回到预览状态,避免状态卡死:@Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { unlockFocus(); // 失败后强制回到预览状态 }
针对你卡住的AE状态问题的补充说明
你代码中卡在STATE_WAITING_PRECAPTURE/STATE_WAITING_NON_PRECAPTURE,是因为提前显示按钮后,相机的AE还没完成从拍照到预览的状态切换。此时aeState可能还处于CONTROL_AE_STATE_PRECAPTURE,不满足进入STATE_PICTURE_TAKEN的条件,导致无限等待。而等相机回到STATE_PREVIEW后,AE状态已经稳定,此时点击按钮就能正常触发拍照流程。
内容的提问来源于stack exchange,提问作者Hichem Acher

