无故无法连接相机服务(RuntimeException)

3
所以我的 Manifest.xml 是正确的:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<application>
...

我还在onPauseonDestroy函数中释放相机,使用了这个函数:

private void releaseCamera() {
    // stop and release camera
    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
    //mPreview instance of CameraPreview (referenced below)
    if (mPreview != null) {
        mPreview.setCamera(null);
    }
}

我在onResume期间只调用一次mCamera = Camera.open();

尽管我按照Stack Overflow和其他来源上的每个示例完全执行操作,但Camera.open()偶尔会失败。

一些使用情况:

  • 启用WiFi打开相机活动(相机工作
  • 没有网络连接打开相机活动(相机失败//奇怪
  • 捕获RuntimeException,然后调用mCamera.takePicture(),活动崩溃并重新加载。(相机工作

所以我完全被难住了...任何想法都将不胜感激:D

如请求,请查看下面的相关代码:

CameraPreiview

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        try {
            // create the surface and start camera preview
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            }
        } catch (IOException e) {
            Log.d(VIEW_LOG_TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void refreshCamera(Camera camera) {
        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }
        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }
        // set preview size and make any resize, rotate or
        // reformatting changes here
        // start preview with new settings
        setCamera(camera);
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        } catch (Exception e) {
            Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        refreshCamera(mCamera);
    }

    public void setCamera(Camera camera) {
        //method to set a camera instance
        mCamera = camera;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
        }

    }
}

示例活动

public class CameraActivity extends Activity {

    private static final String TAG = "CameraActivity";

    private Camera mCamera;
    private CameraPreview mPreview;
    private Camera.PictureCallback mPicture;
    private ImageButton capture;
    private Context myContext;
    private LinearLayout cameraPreview;

    // Required to remove the camera if onPause did not
    @Override
    public void onDestroy() {
        releaseCamera();
        super.onDestroy();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_test);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        myContext = this;
        initialize();
    }


    //Code to find the id for the traditional back facing camera
    private int findBackFacingCamera() {
        int cameraId = -1;
        //Search for the back facing camera
        //get the number of cameras
        int numberOfCameras = Camera.getNumberOfCameras();
        //for every camera check
        for (int i = 0; i < numberOfCameras; i++) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                cameraId = i;
                cameraFront = false;
                break;
            }
        }
        return cameraId;
    }

    @Override
    public void onResume() {
        super.onResume();
        //If there is no camera on the device, inform the user.
        if (!hasCamera(myContext)) {
            Toast toast = Toast.makeText(myContext, "Sorry, your phone does not have a camera!", Toast.LENGTH_LONG);
            toast.show();
        }
        //release the camera if it's in use.
        releaseCamera();
        if (mCamera == null) {
            //if the back facing camera does not exist
            if (findBackFacingCamera() < 0) {
                Toast.makeText(this, "No back facing camera found.", Toast.LENGTH_LONG).show();
            } else {
                try {
                    //Open the back facing camera, note that Camera.open() gives the same error.
                    mCamera = Camera.open(findBackFacingCamera());
                    mCamera.setDisplayOrientation(90);  //Show in Portrait
                    mPicture = getPictureCallback();
                    mPreview.refreshCamera(mCamera);
                } catch (RuntimeException e) {
                    e.printStackTrace();
                    Toast.makeText(this, "Could not connect to camera.", Toast.LENGTH_LONG).show();
                }
            }
        }
    }


    public void initialize() {
        cameraPreview = (LinearLayout) findViewById(R.id.camera_preview);
        mPreview = new CameraPreview(myContext, mCamera);
        cameraPreview.addView(mPreview);

        capture = (ImageButton) findViewById(R.id.button_capture);
        capture.setOnClickListener(captureListener);
    }


    @Override
    protected void onPause() {
        super.onPause();
        //when on Pause, release camera in order to be used from other applications
        releaseCamera();
    }


    private void captureComplete() {
        //...
    }

    private Camera.PictureCallback getPictureCallback() {
        Camera.PictureCallback picture = new Camera.PictureCallback() {

            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                //make a new picture file
                mFile = ImageUtility.getOutputMediaFile(ImageUtility.MEDIA_TYPE_IMAGE);
                Log.i(TAG, (mFile == null) + ": ");
                if (mFile == null) {
                    return;
                }

                mPreview.refreshCamera(mCamera);
                mBackgroundHandler.post(new ImageUtility.ImageSaver(getApplicationContext(), data, mFile, new Callable() {
                    @Override
                    public Object call() throws Exception {
                        captureComplete();
                        return null;
                    }
                }));
            }
        };
        return picture;
    }

    View.OnClickListener captureListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mCamera != null) {
                mCamera.autoFocus(new Camera.AutoFocusCallback() {
                    @Override
                    public void onAutoFocus(boolean success, Camera camera) {
                        mPicture = getPictureCallback();
                        mPreview.refreshCamera(camera);
                        camera.takePicture(null, null, mPicture);
                    }
                });
            } else {
                throw new NullPointerException();
            }
        }
    };

    private void releaseCamera() {
        // stop and release camera
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        if (mPreview != null) {
            mPreview.setCamera(null);
        }
    }
}

你是在模拟器上测试还是在真实设备上测试?你测试的API级别是哪个? - Sharp Edge
我正在华为Mate 7上进行测试,compileSdkVersion 21,minSdkVersion 14,targetSdkVersion 21。设备本身运行在API级别19上。 - Werner Raath
你能确认这种行为在其他设备上是否存在吗?如果没有,那么使用带有模拟相机的模拟器如何?如果问题仍然存在,那么你需要发布与相机相关的整个代码。 - Sharp Edge
已确认其他安装该应用程序的设备也是相同的。我会为您添加代码。 - Werner Raath
1个回答

0

有些更改你可以做,因为我也已经在Camera API上工作了3个月。

在你的CameraPreview构造函数中,添加这一行:

    if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) // add this
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

在你的CameraPreview类中的surfaceDestroyed()方法中,你应该在释放相机资源后立即删除回调函数:
this.getHolder().removeCallback(this);

除了更改上述内容,我无法从您的CameraActivity中找到太多信息,因为您使用了自动对焦和其他功能... 我使用FrameLayout作为容器来运行预览。


我已经检查了API级别,以确保我为android.hardware.cameraandroid.hardware.camera2使用单独的Activity。不幸的是,删除回调并没有什么作用。我的Activity非常简单。我将在代码中添加一些注释以解释更多内容。 - Werner Raath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接