You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义相机调用takePicture抛出RuntimeException:takePicture failed问题排查

解决Camera.takePicture()抛出RuntimeException的问题

先聚焦核心问题:你遇到的java.lang.RuntimeException: takePicture failed,主要根源是Camera实例的跨线程调用违规,再加上可能的预览未就绪问题,下面分点给出具体解决方案:

1. 修复Camera API的线程调用问题

旧版android.hardware.Camera有严格的线程约束:所有Camera操作(打开、设置参数、调用takePicture等)必须在同一个线程执行。你的代码在CameraHandlerThread子线程中打开了Camera,但在主线程的点击事件里直接调用mCamera.takePicture(),这种跨线程操作会触发Native层的崩溃。

修改方式:把拍照操作移到Camera所在的HandlerThread中执行:

// 在CameraFragment中新增方法,通过HandlerThread的Handler执行拍照逻辑
private void takePictureInCameraThread() {
    if (mThread != null && mThread.mHandler != null) {
        mThread.mHandler.post(new Runnable() {
            @Override
            public void run() {
                Camera camera = mThread.getCamera();
                if (camera != null) {
                    camera.takePicture(null, null, mPicture);
                }
            }
        });
    }
}

// 修改点击事件,改用上面的方法
ivCaptureImage.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        takePictureInCameraThread();
    }
});

2. 确保预览完全就绪后再允许拍照

如果预览还没完成初始化就调用takePicture,也会导致失败。你可以在CameraPreview类中添加状态标记,确认预览就绪后再响应拍照:

// 在CameraPreview类中添加就绪标记和获取方法
private boolean isPreviewReady = false;

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // 原有预览初始化代码...
    if (mCamera != null) {
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
            isPreviewReady = true; // 标记预览已就绪
        } catch (IOException e) {
            e.printStackTrace();
            isPreviewReady = false;
        }
    }
}

public boolean isPreviewReady() {
    return isPreviewReady;
}

然后在点击事件中先检查状态:

ivCaptureImage.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mPreview != null && mPreview.isPreviewReady()) {
            takePictureInCameraThread();
        }
    }
});

3. 规范Camera的生命周期管理

在Fragment的生命周期中及时释放和重新初始化Camera,避免实例失效:

@Override
public void onPause() {
    super.onPause();
    if (mThread != null && mThread.getCamera() != null) {
        mThread.mHandler.post(new Runnable() {
            @Override
            public void run() {
                Camera camera = mThread.getCamera();
                camera.stopPreview();
                camera.release();
                mThread.handlerCamera = null;
            }
        });
    }
}

@Override
public void onResume() {
    super.onResume();
    newOpenCamera(); // 重新打开相机
    // 重新初始化预览视图
    mPreview = new CameraPreview(getContext(), mCamera, activity);
    mPreview.setCameraDisplayOrientation(activity, CAMERA_ID, mCamera);
    preview.removeAllViews();
    preview.addView(mPreview);
}

关于重复错误日志的说明

你看到两条相同的错误日志,是因为Android系统默认的异常处理器和应用进程的异常处理器都捕获了这个崩溃并输出。解决核心的takePicture失败问题后,重复日志的情况也会随之消失。

内容的提问来源于stack exchange,提问作者eyes enberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:41:02