Android相机:应用程序通过NULL表面

Posted

技术标签:

【中文标题】Android相机:应用程序通过NULL表面【英文标题】:Android Camera: app passed NULL surface 【发布时间】:2015-07-31 21:54:51 【问题描述】:

我发现了几个关于此的问题,但没有答案,所以希望有人能对此有所了解。当我尝试交换相机时,我调用了下面的 swapCamera 函数。然而,相机预览只是冻结(应用程序没有冻结,虽然只是实时相机预览)。

当我第一次打开应用程序时,一切正常。然而,我注意到了一些有趣的事情。当我注销 _surfaceHolder 对象(即我的 SurfaceHolder 对象)的内存地址时,它给了我一个值,但每当我在应用程序完成启动后查询该值时,该内存地址已更改。

此外,当我 swapCamera 时它给我的错误非常令人困惑。在将 _surfaceHolder 传递给_camera.setPreviewDisplay(_surfaceHolder); 的相机之前,我已注销 并且在传入之前不为空。

非常感谢任何帮助。

我注意到一些有趣的行为

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();
    

【问题讨论】:

你有可以包含的 logcat 吗? 唯一的 logcat 值是这一行:D/Camera﹕ app passed NULL surface swapCamera 被调用时你是否在主 UI 线程上? 是的,它是一个主线程调用。唯一的异步调用是第一次创建的 surfaceHolder 回调 有 5 个这样的问题,没有一个有答案。我刚刚找到了一个解决方案,添加已解决可能会帮助其他人找到它并且我认为它更有用 【参考方案1】:

所以经过大量调试和挖掘,我发现罪魁祸首是 onResume 函数。

在其中,我正在“刷新”相机变量,以防它在上下文切换之间丢失。

public void onResume()

    super.onResume();
    _cameraPreview = new CameraPreview(getActivity());

这导致我的 surfaceHolder 被重新创建。我不确定它为什么会导致 null,但我认为因为我创建了 SurfaceHolder 的新实例,内部 android 代码保留了对旧(现在为 null)SurfaceHolder 的引用。通过从 onResume 中删除我的“刷新”(即重新实例化)调用,问题得到了解决。

我认为该错误具有误导性,因为它说传递了一个空表面,但那是因为我认为即使您创建了一个新表面并传入它,它也会保留对空表面Holder的引用(它似乎现在使用旧的 null一个反正)。因此,如果您收到此错误,请检查您是否没有重新创建 surfaceHolder 并将其传入。

【讨论】:

以上是关于Android相机:应用程序通过NULL表面的主要内容,如果未能解决你的问题,请参考以下文章

Android:Camera2错误参数传递给相机服务

代号为一个相机背景

android自定义相机拉伸surfaceview

在android中使用没有预览或表面的相机

相机中使用的Android模糊surfaceview

当相机在Android中的表面视图上以编程方式截屏