简体   繁体   English

Android Camera:app传递了NULL表面

[英]Android Camera: app passed NULL surface

I've found several questions on this but no answers so here's hoping someone might have some insight. 我已经找到了几个问题,但没有答案,所以这里希望有人可能有一些见解。 When I try to swap the camera I call the swapCamera function below. 当我尝试交换相机时,我调用下面的swapCamera功能。 However the camera preview just freezes (the app is not frozen though just the live camera preview). 然而,相机预览只是冻结(虽然只是实时相机预览,应用程序不会冻结)。

When I open the app for the first time everything works just fine. 当我第一次打开应用程序时,一切正常。 However I noticed something interesting. 但是我注意到一些有趣的事 When I log out the memoryaddress of the _surfaceHolder object (ie my SurfaceHolder object) it gives me one value, but whenever I query that value after the app has finished launching and everything, that memory address has changed. 当我注销_surfaceHolder对象的memoryaddress(即我的SurfaceHolder对象)时,它给了我一个值,但每当我在应用程序完成启动后查询该值时,该内存地址都已更改。

Further still, the error it gives me when I swapCamera is very confusing. 更进一步,当我换掉相机时它给我的错误是非常令人困惑的。 I logged out _surfaceHolder before I passed it to the camera in _camera.setPreviewDisplay(_surfaceHolder); 在我将它传递给_camera.setPreviewDisplay(_surfaceHolder);的相机之前,我注销了_surfaceHolder _camera.setPreviewDisplay(_surfaceHolder); and it is NOT null before it's passed in. 并且它在传入之前不为null。

Any help is greatly appreciated. 任何帮助是极大的赞赏。

I've noticed some interesting behaviour 我注意到了一些有趣的行为

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
{
    private SurfaceHolder _surfaceHolder;
    private Camera _camera;
    boolean _isBackFacing;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        _camera = camera;
        _isBackFacing = true;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        _surfaceHolder = getHolder();
        _surfaceHolder.addCallback(this);
    }

    void refreshCamera()
    {
        try {
            _camera.setPreviewDisplay(_surfaceHolder);
            _camera.startPreview();
        } catch (IOException e) {
            Log.d("iCamera", "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
//        The Surface has been created, now tell the camera where to draw the preview.
        refreshCamera();
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        // empty. Take care of releasing the Camera preview in your activity.
        _surfaceHolder.removeCallback(this);
    }

    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.

        if (_surfaceHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        try {
            _camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes her
        _camera.setDisplayOrientation(90);

        // _startPoint preview with new settings
        refreshCamera();
    }

    public void swapCamera()
    {
        Camera cam = null;
        int cameraCount = Camera.getNumberOfCameras();
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        _camera.stopPreview();
        _camera.release();
        for (int i = 0; i < cameraCount; i++)
        {
            Camera.getCameraInfo(i,cameraInfo);
            if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && _isBackFacing == true)
            {
                try
                {
                    _camera = Camera.open(i);

                }catch (RuntimeException e)
                {
                    Log.e("Error","Camera failed to open: " + e.getLocalizedMessage());
                }
            }

            if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK && _isBackFacing == false)
            {
                try
                {
                    _camera = Camera.open(i);
                }catch (RuntimeException e)
                {
                    Log.e("Error","Camera failed to open: " + e.getLocalizedMessage());
                }
            }
        }

        _isBackFacing = !_isBackFacing;
        refreshCamera();
    }
}

So after much debugging and digging what I found to be the culprit was the onResume function. 所以经过多次调试和挖掘我发现的罪魁祸首是onResume函数。

In it, I was 'refreshing' the camera variable in case it got lost between context switching. 在其中,我正在“刷新”相机变量,以防它在上下文切换之间丢失。

public void onResume()
{
    super.onResume();
    _cameraPreview = new CameraPreview(getActivity());
}

This was causing my surfaceHolder to be created anew. 这导致我的surfaceHolder重新创建。 I'm not exactly sure why it would cause a null, but I think because I created a new instance of a SurfaceHolder, the internal Android code was keeping a reference to the old (now null) SurfaceHolder. 我不确定为什么会导致null,但我认为因为我创建了一个SurfaceHolder的新实例,内部Android代码保留了对旧(现在为空)SurfaceHolder的引用。 By removing my 'refresh' (ie reinstantiating) call from onResume the problem was fixed. 通过从onResume删除我的'刷新'(即重新实例化)调用,问题得到解决。

The error is misleading I think because its saying a null surface was passed but thats because I think its keeping a reference to a null surfaceHolder even if you created a new one and passed that in (it seems to use the OLD now null one anyways). 这个错误是误导的我认为因为它说传递了null表面但是那是因为我认为它保持对null surfaceHolder的引用,即使你创建了一个新的并传递了它(它似乎使用OLD现在为null) 。 So if you get this error, check that you aren't re-creating the surfaceHolder and passing it in. 因此,如果您收到此错误,请检查您是否正在重新创建surfaceHolder并将其传入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM