Android 相机:应用程序传递了 NULL 表面
Android Camera: app passed NULL surface
我发现了几个关于此的问题,但没有答案,所以希望有人能提供一些见解。当我尝试交换相机时,我调用了下面的 swapCamera 函数。但是,相机预览只是冻结(虽然只是实时相机预览,但应用程序并未冻结)。
当我第一次打开应用程序时,一切正常。但是我注意到了一些有趣的事情。当我注销 _surfaceHolder 对象(即我的 SurfaceHolder 对象)的内存地址时,它会给我一个值,但每当我在应用程序完成启动和所有操作后查询该值时,该内存地址都已更改。
此外,当我 swapCamera 时它给我的错误非常令人困惑。我在 _camera.setPreviewDisplay(_surfaceHolder);
中将它传递给相机之前注销了 _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();
}
}
经过大量调试和挖掘,我发现罪魁祸首是 onResume 函数。
在其中,我是 'refreshing' 相机变量,以防它在上下文切换之间丢失。
public void onResume()
{
super.onResume();
_cameraPreview = new CameraPreview(getActivity());
}
这导致我的 surfaceHolder 被重新创建。我不确定为什么它会导致 null,但我认为因为我创建了 SurfaceHolder 的新实例,所以内部 Android 代码保持对旧(现在为 null)SurfaceHolder 的引用。通过从 onResume 中删除我的 'refresh'(即重新实例化)调用,问题得到解决。
我认为该错误具有误导性,因为它说传递了一个空表面,但那是因为我认为它保持对空表面持有人的引用,即使您创建了一个新表面并将其传入(它似乎使用旧的现在无论如何都是空的)。因此,如果您遇到此错误,请检查您是否没有重新创建 surfaceHolder 并将其传入。
我发现了几个关于此的问题,但没有答案,所以希望有人能提供一些见解。当我尝试交换相机时,我调用了下面的 swapCamera 函数。但是,相机预览只是冻结(虽然只是实时相机预览,但应用程序并未冻结)。
当我第一次打开应用程序时,一切正常。但是我注意到了一些有趣的事情。当我注销 _surfaceHolder 对象(即我的 SurfaceHolder 对象)的内存地址时,它会给我一个值,但每当我在应用程序完成启动和所有操作后查询该值时,该内存地址都已更改。
此外,当我 swapCamera 时它给我的错误非常令人困惑。我在 _camera.setPreviewDisplay(_surfaceHolder);
中将它传递给相机之前注销了 _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();
}
}
经过大量调试和挖掘,我发现罪魁祸首是 onResume 函数。
在其中,我是 'refreshing' 相机变量,以防它在上下文切换之间丢失。
public void onResume()
{
super.onResume();
_cameraPreview = new CameraPreview(getActivity());
}
这导致我的 surfaceHolder 被重新创建。我不确定为什么它会导致 null,但我认为因为我创建了 SurfaceHolder 的新实例,所以内部 Android 代码保持对旧(现在为 null)SurfaceHolder 的引用。通过从 onResume 中删除我的 'refresh'(即重新实例化)调用,问题得到解决。
我认为该错误具有误导性,因为它说传递了一个空表面,但那是因为我认为它保持对空表面持有人的引用,即使您创建了一个新表面并将其传入(它似乎使用旧的现在无论如何都是空的)。因此,如果您遇到此错误,请检查您是否没有重新创建 surfaceHolder 并将其传入。