【问题标题】:method called after release() exception unable to resume with android camera释放()异常后调用的方法无法使用android相机恢复
【发布时间】: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
}

关于如何解决这个问题的任何想法?

【问题讨论】:

    标签: java android exception callback camera


    【解决方案1】:

    我也遇到了同样的问题。 mCamera.setPreviewCallback(null); 没有帮助。在我的活动中,我已将此添加到releaseCamera

    mPreview.getHolder().removeCallback(mPreview);
    

    现在可以使用了。

    【讨论】:

    • 这对我有用。我把它放在mCamera.setPreviewCallback(null)mCamera.release()之间的onPause
    • 也为我工作。谢谢。
    • 这段代码中的mPreview到底是什么?我收到了同样的错误,但似乎没有任何合适类型的对象可以传递给这个方法。我唯一的回调是Camera.PreviewCallback,而不是SurfaceHolder.CallbackmPreview.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);
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-08-06
                • 2022-12-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多