释放()异常后调用的方法无法使用android相机恢复
Posted
技术标签:
【中文标题】释放()异常后调用的方法无法使用android相机恢复【英文标题】:method called after release() exception unable to resume with android camera 【发布时间】:2012-02-10 17:29:01 【问题描述】:在开发相机应用时,我遇到了一个仅在我切换到其他应用时发生的异常(我的应用为onPause()
)。
01-15 17:22:15.017: E/androidRuntime(14336): FATAL EXCEPTION: main
01-15 17:22:15.017: E/AndroidRuntime(14336): java.lang.RuntimeException: Method called after release()
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.hardware.Camera.setPreviewDisplay(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.hardware.Camera.setPreviewDisplay(Camera.java:357)
01-15 17:22:15.017: E/AndroidRuntime(14336): at com.sora.cbir.yuki.image.leaf.CameraPreview.surfaceCreated(CameraPreview.java:32)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.SurfaceView.updateWindow(SurfaceView.java:551)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:213)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.View.dispatchWindowVisibilityChanged(View.java:4075)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.ViewRoot.performTraversals(ViewRoot.java:858)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.view.ViewRoot.handleMessage(ViewRoot.java:1995)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.os.Handler.dispatchMessage(Handler.java:99)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.os.Looper.loop(Looper.java:150)
01-15 17:22:15.017: E/AndroidRuntime(14336): at android.app.ActivityThread.main(ActivityThread.java:4389)
01-15 17:22:15.017: E/AndroidRuntime(14336): at java.lang.reflect.Method.invokeNative(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336): at java.lang.reflect.Method.invoke(Method.java:507)
01-15 17:22:15.017: E/AndroidRuntime(14336): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
01-15 17:22:15.017: E/AndroidRuntime(14336): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
01-15 17:22:15.017: E/AndroidRuntime(14336): at dalvik.system.NativeStart.main(Native Method)
我做了一些研究,发现我需要添加
mCamera.setPreviewCallback(null);
作为 Android 相机堆栈的解决方法
我的onPause()
现在看起来像这样:
@Override
protected void onPause()
super.onPause();
try
// release the camera immediately on pause event
//releaseCamera();
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
catch(Exception e)
e.printStackTrace();
还有我的onResume()
:
@Override
protected void onResume()
super.onResume();
try
mCamera.setPreviewCallback(null);
mCamera = getCameraInstance();
//mCamera.setPreviewCallback(null);
mPreview = new CameraPreview(Imageupload.this, mCamera);//set preview
preview.addView(mPreview);
catch (Exception e)
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
最后是我的getCameraInstance()
方法:
public Camera getCameraInstance()
Camera camera = null;
try
camera = Camera.open(); // attempt to get a Camera instance
catch (Exception e)
// Camera is not available (in use or does not exist)
Camera.Parameters parameters = camera.getParameters();
//mPreviewSize = getBestPreviewSize(parameters, wt, ht);
//mPictureSize = getBestPictureSize(parameters, wt, ht);
//Shift W & H => if camera rotates 90 deg
mPreviewSize = getOptimalPreviewSize(parameters, wt, ht); //original => wt,ht
mPictureSize = getOptimalPictureSize(parameters, wt, ht); //original => wt,ht
Log.d("CAMERA", "SCREEN RESOLUTION H: "+ht);
Log.d("CAMERA", "SCREEN RESOLUTION W: "+wt);
Log.d("CAMERA", "PREVIEW RESOLUTION H: "+mPreviewSize.height);
Log.d("CAMERA", "PREVIEW RESOLUTION W: "+mPreviewSize.width);
Log.d("CAMERA", "PICTURE RESOLUTION H: "+mPictureSize.height);
Log.d("CAMERA", "PICTURE RESOLUTION W: "+mPictureSize.width);
//set preview size based on device screen
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
//set picture size based on device screen
parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
//set output camera mode
parameters.setPictureFormat(PixelFormat.JPEG);
//set focous mode
parameters.setFocusMode(FOCUS_MODE_AUTO);
//set flash mode
parameters.setFlashMode("auto");
List<int[]> fps = parameters.getSupportedPreviewFpsRange();
//System.out.println("FPS size: " +fps.size());
//System.out.println("MAX FPS:"+(fps.get(fps.size()-1)[1])/1000);
//log min and max camera supported fps
Log.d("CAMERA", "CAMERA MAX FPS: "+(fps.get(fps.size()-1)[1])/1000);
Log.d("CAMERA", "CAMERA MIN FPS: "+(fps.get(fps.size()-1)[0])/1000);
if(camera_fps)
parameters.setPreviewFpsRange(fps.get(fps.size()-1)[1], fps.get(fps.size()-1)[1]);
//set camera parameters
camera.setParameters(parameters);
Toast.makeText(getApplicationContext(), "Your device are capable of previewing @" + fps.get(fps.size()-1)[1]/1000+"fps!",Toast.LENGTH_SHORT).show();
return camera; // returns null if camera is unavailable
关于如何解决这个问题的任何想法?
【问题讨论】:
【参考方案1】:我也遇到了同样的问题。 mCamera.setPreviewCallback(null);
没有帮助。在我的活动中,我已将此添加到releaseCamera
:
mPreview.getHolder().removeCallback(mPreview);
现在可以使用了。
【讨论】:
这对我有用。我把它放在mCamera.setPreviewCallback(null)
和mCamera.release()
之间的onPause
。
也为我工作。谢谢。
这段代码中的mPreview
到底是什么?我收到了同样的错误,但似乎没有任何合适类型的对象可以传递给这个方法。我唯一的回调是Camera.PreviewCallback
,而不是SurfaceHolder.Callback
(mPreview.getHolder()
是你的SurfaceHolder
,对吧?)
类似这样的:private CameraPreview mPreview;
onResume:mPreview = new CameraPreview(this, mCamera, preview, null);
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
抱歉,很久以前的事了,不太记得了。【参考方案2】:
@ookami.kb 解决方案也对我有用,@srunni 也发表了评论。
public void onPause()
super.onPause();
if (mCamera != null)
mCamera.setPreviewCallback(null);
mPreview.getHolder().removeCallback(mPreview);
mCamera.release();
我也删除了 onDestroy 方法。
【讨论】:
你为什么还要从 OnDestroy 中删除 - 完全没有意义!【参考方案3】:文档清楚地说camera.release()
释放所有相机资源。调用后相机参考不能再使用了。
如果您想再次使用相机,您必须通过open(int)
方法获取它。
camera docs 中都有描述。
【讨论】:
你能再检查一下代码吗?我已经添加了您的建议并根据 android dev 的指南修复了其余部分,但仍然没有结果 还是同样的错误?它清楚地写着Method called after release()
和下一行at android.hardware.Camera.setPreviewDisplay(..)
。所以你必须在release()
之后调用setPreviewDisplay()
在我的 onResume 中,我需要恢复我的预览,因此,使用 mCamera.open()...,然后设置我的所有参数并再次预览显示表面,对吗?必须在 release() 之后调用。如果这导致异常,我该如何正确恢复它?
无论如何,我已经用 try catch 语句包围了我的 setPreviewDisplay(..),现在系统将报告异常但继续我的任务;我会将此视为一种解决方法:)如果您认为不是这样,非常欢迎您添加任何内容:)
这不是正确的答案。根据其他答案,removeCallback()
解决了该问题。来自谷歌的文档不完整。【参考方案4】:
要正确恢复,您需要这样做:
@Override
public void onResume()
super.onResume();
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null)
initializeCamera(); // Local method to handle camera initialization
protected void initializeCamera()
// Get an instance of Camera Object
mCamera = getCameraInstance();
// create a basic camera preview class that can be included in a View layout.
mPreview=new CameraPreview(this,mCamera);
//add your preview class to the FrameLayout element.
preview.addView(mPreview);
//Trigger capturing an image by calling the Camera.takePicture() method.
captureButton.setOnClickListener(
new View.OnClickListener()
@Override
public void onClick(View v)
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
);
同时也提醒一下,在 oncreate() 中除了定义 FrameLayout 预览和 Button captureButton 之外什么都不做。
【讨论】:
【参考方案5】:@Override public void surfaceDestroyed(SurfaceHolder surfaceHolder)
this.getHolder().removeCallback(this);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
Log.e("surfaceDestroyed", "surfaceDestroyed");
并在 Resume 函数中重新初始化相机。
【讨论】:
【参考方案6】:添加到 okambi 的答案。
这是恢复时搞砸一切的功能:
public void surfaceCreated(SurfaceHolder holder)
// The Surface has been created, now tell the camera where to draw the preview.
try
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
catch (IOException e)
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
try 没有捕捉到抛出的异常。即mCamera不存在,然后当它尝试调用setPreviewDisplay(holder)时,出现crash。
因此,通过删除回调,不会调用此 surfaceCreated 并避免崩溃。
Google 对此的记录很差。
【讨论】:
【参考方案7】:我放了
mPreview.getHolder().removeCallback(mPreview);
之间。
mCamera.setPreviewCallback(null);
和
mCamera.release();
它对我有用。
@Override
protected void onPause()
super.onPause();
this.saveTextEdits();
try
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
**mPreview.getHolder().removeCallback(mPreview);**
mCamera.release();
mCamera = null;
catch (Exception e)
【讨论】:
【参考方案8】:我遇到了同样的问题,我通过 - 在 Preview 类的 surfaceDestroyed(SurfaceHolder holder) 方法中添加 mCamera = null;。
public void surfaceDestroyed(SurfaceHolder holder)
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null)
mCamera.stopPreview();
mCamera.release();
mCamera = null;
和 - 添加
camera = Camera.open();
camera.startPreview();
params = camera.getParameters();
preview.setCamera(camera);
在我的 CameraActivity 的 OnResume() 方法中。
【讨论】:
【参考方案9】:如果你得到:
尝试调用虚方法'void android.hardware.Camera.setPreviewCallback(android.hardware.Camera$PreviewCallback)' 在空对象引用上
我同意@ookami.kb - mCamera.setPreviewCallback(null);
还不够,后面还要加上这个:
mCameraView.getHolder().removeCallback(mCameraView);
【讨论】:
以上是关于释放()异常后调用的方法无法使用android相机恢复的主要内容,如果未能解决你的问题,请参考以下文章