如何在Android模拟器中修复“无法连接到相机服务”异常

35

当我在模拟器中运行我的Android应用时,我遇到了一个无法连接到相机服务的异常。我已经阅读了各种现有帖子,但都没有解决这个问题。显然是Camera.open()调用失败了。我最终想要在模拟器中使用网络摄像头,因为许多SO帖子都讨论了这个问题,但现在只想让应用程序不出错运行。我不关心是否显示任何相机视频,因为除了相机以外还有其他需要测试的功能,并且主要还是在我的设备上测试相机。

我的清单似乎没问题。它包含以下行:

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
在我的AVD管理器中,我已将前置和后置摄像头均设置为“模拟”,SD卡的值为64。这些似乎是推荐值。完整的堆栈跟踪现在如下所示。解决方案必须是直截了当的,但是该怎么做呢?
10-09 08:14:32.375    2628-2628/com.allinlearning.AILAndroidScanner E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.allinlearning.AILAndroidScanner, PID: 2628
java.lang.RuntimeException: Fail to connect to camera service
        at android.hardware.Camera.native_setup(Native Method)
        at android.hardware.Camera.<init>(Camera.java:350)
        at android.hardware.Camera.open(Camera.java:309)
        at com.allinlearning.AILAndroidScanner.AsynCamPreview.surfaceCreated(AsynCamPreview.java:104)
        at android.view.SurfaceView.updateWindow(SurfaceView.java:572)
        at android.view.SurfaceView.access$000(SurfaceView.java:86)
        at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:175)
        at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:847)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1871)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
        at android.view.Choreographer.doCallbacks(Choreographer.java:574)
        at android.view.Choreographer.doFrame(Choreographer.java:544)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
整个类的代码如下所示。再次提醒,会抛出异常的是 Camera.open() 调用:
import java.io.IOException;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.SurfaceHolder;
import android.webkit.MimeTypeMap;
import android.widget.ImageView;

public class AsynCamPreview extends MainActivity
        implements SurfaceHolder.Callback,  Camera.PreviewCallback
{

    private Camera mCamera;
    public Camera.Parameters params;
    private SurfaceHolder sHolder;
    private ImageView myCameraPreview = null;
    private Bitmap mBitmap = null;

    // data arrays
    private int[] pixels = null;
    private float[] floatpixels = null;
    private byte[] FrameData = null;

    // Camera params
    public float maxZoom;
    private int imageFormat;
    private int previewSizeWidth;
    private int previewSizeHeight;
    private int camId = 1;

    // flags and counts
    private boolean bProcessing = false;
    private int frameCount = 0;
    private boolean doProcessing = false;
    public boolean mProcessInProgress = false;

    public static final String TAG = "AsynCamPreview";

    private long mTiming[] = new long[50];
    private int mTimingSlot = 0;

    Handler mHandler = new Handler(Looper.getMainLooper());

    static {
//      System.loadLibrary("ImageProcessing");
        Log.i(TAG, "Native library loaded");
    }

    public AsynCamPreview(int previewLayoutWidth, int previewLayoutHeight, ImageView cameraPreview)
    {
        previewSizeWidth = previewLayoutWidth;
        previewSizeHeight = previewLayoutHeight;
        myCameraPreview =cameraPreview;
    }


    @Override
    public void onPreviewFrame(byte[] data, Camera camera)
    {
        // Do nothing for now
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        sHolder = holder;
        if (camId == 0) {
            mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
        }
        else {
            mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        }

        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.setPreviewCallback(this);
        } catch (IOException e) {
            mCamera.release();
            mCamera= null;
        }

        params = mCamera.getParameters();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
        // TODO Auto-generated method stub
        params = mCamera.getParameters();
        List<Camera.Size> sizes = params.getSupportedPictureSizes();
        this.params.setPreviewSize(previewSizeWidth, previewSizeHeight);

        mBitmap = Bitmap.createBitmap(previewSizeWidth, previewSizeHeight,
                Bitmap.Config.ARGB_8888);
        myCameraPreview.setImageBitmap(mBitmap);

        pixels = new int[previewSizeWidth * previewSizeHeight];
        //floatpixels = new float[previewSizeWidth * previewSizeHeight * 3];
        imageFormat = params.getPreviewFormat();
        mCamera.setParameters(params);
        mCamera.startPreview();

    }

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

    @Override
    public void onPause() {
        this.mCamera.stopPreview();
    }

}

请问您能发布Java代码吗?还有完整的堆栈跟踪信息吗? - aProperFox
Tyler,根据您的要求,我已更新了问题。 - Alyoshak
谢谢,虽然我们可能需要更多的Java代码。你可以发布整个类吗?我猜是mCamera的声明没有做好。 - aProperFox
1
一旦设置了Camera变量,似乎并没有做太多事情,除了尝试打开它。但是这段代码在我的Eclipse项目中针对设备正常工作(现在我在模拟器上使用IntelliJ)。 - Alyoshak
7个回答

43

来自Android开发者文档

如果摄像头已经被另一个应用程序使用,则调用Camera.open()会抛出异常,因此我们将其包装在try块中。

尝试将该代码包装在try catch块中,如下所示:

try {
    releaseCameraAndPreview();
    if (camId == 0) {
        mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
    }
    else {
        mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
    }
} catch (Exception e) {
    Log.e(getString(R.string.app_name), "failed to open Camera");
    e.printStackTrace();
}

然后在某个地方添加这个函数:

private void releaseCameraAndPreview() {
    myCameraPreview.setCamera(null);
    if (mCamera != null) {
        mCamera.release();
        mCamera = null;
    }
}

在我看来,调用releaseCameraAndPreview()方法实际上是解决问题的关键。相机一定以某种方式被使用了,尽管我不知道具体原因。无论如何,为什么要调用myCameraPreview.setCamera(null)呢?我不得不将其注释掉。myCameraPreview是一个ImageView对象,没有setCamera()方法。 - Alyoshak
我刚从Android开发文档中找到了这个。我觉得可能是需要用mcamera = null来初始化相机。我的研究显示大多数人都需要添加这个。要么就是相机正在被其他应用程序使用 :P - aProperFox
1
我只想指出,如果设备上的相机不工作,也会出现这个错误。 - Automatico
@Alyoshak:可能出现这种情况的一个场景是:在Facebook视频通话中,最小化会创建一个较小的视频通话对话框,并且不会释放摄像头。当你从另一个应用程序使用相机时,就会出现此错误。 - Harish Vishwakarma
我的相机预览是什么? - AlexS

9

在Android 6.0中,如果您没有检查清单授权,则可能会出现此错误:

    //If authorisation not granted for camera
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
        //ask for authorisation
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 50);
    else
        //start your camera
        this.startCamera();

9

OP在他的问题中提到了这一点,但我的问题是我忘记在我的AVD模拟器设置中启用相机仿真:

在此输入图片描述


我已经在AVD中启用了此选项,但我的模拟器仍然出现此错误。我错过了什么吗? - SweetWisher ツ
我已经在AVD中启用了此选项,但是在模拟器中仍然出现了这个错误。我有什么遗漏的吗? - SweetWisher ツ

5

使用

if (ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
  ActivityCompat.requestPermissions(CodeScanner.this, new String[]{android.Manifest.permission.CAMERA}, 50);
}

对我来说起作用了


我也是,完全忘记了新的Android需要运行时权限 :-) - TSGames

3

1.在清单文件中使用以下权限,并始终将权限置于应用程序标记之上。

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
    android:name="android.hardware.camera"
    android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" />

2. 当相机被其他服务(如MediaRecorder)使用时,请使用“解锁”功能。

camera.unlock();
recorder.setCamera(camera);

2.正确释放相机,我更倾向于使用锁定功能,以便其他应用程序可以安全地访问并进行第二次使用(如果我们重新打开的话)。

if (camera != null) {
        camera.lock();
        camera.stopPreview();
        camera.release();
        camera = null;
    }

2

如果您定期看到白屏而不是摄像头画面,请使用以下方法:

private void releaseCameraAndPreview() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCameraView.getHolder().removeCallback(mCameraView);
            mCamera.release();
            mCamera = null;
        }
    }

并将其放在这里。
try {
            releaseCameraAndPreview();
            mCamera = getCameraInstance();
        }...

在这里

@Override
    protected void onPause() {
        super.onPause();
        releaseCameraAndPreview();
    }

-1
如果您正在使用Surface View并且使用类似以下代码的内容:
 Observable.create(CameraUtils.getCameraOnSubscribe())
                    .subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(camera -> {

                 mCamera = camera.open();
...    
}};

然后将 mCamera=camera; 替换掉。


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