致命异常 - 在 Camera.release() 被称为 HTC ONE M9 之后正在使用相机

Posted

技术标签:

【中文标题】致命异常 - 在 Camera.release() 被称为 HTC ONE M9 之后正在使用相机【英文标题】:Fatal Exception - Camera is being used after Camera.release() was called HTC ONE M9 【发布时间】:2016-12-06 13:41:19 【问题描述】:

我正在检查我的 surfaceView 项目是否运行良好,因此我在我的妻子 Galaxy s7 G930F 上进行了尝试,它运行良好,当我尝试在我的 HTC ONE M9 上运行时它甚至没有完全移动,一直在崩溃。这是一个奇怪的问题,这两款手机都在 android 6 上运行。在尝试运行时,我附上了一个日志:

 E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.example.arturs.androidmirrorapplicationv2, PID: 15974
              java.lang.RuntimeException: Camera is being used after Camera.release() was called
                  at android.hardware.Camera.setPreviewSurface(Native Method)
                  at android.hardware.Camera.setPreviewDisplay(Camera.java:923)
                  at com.example.arturs.androidmirrorapplicationv2.CameraView.surfaceCreated(CameraView.java:46)
                  at android.view.SurfaceView.updateWindow(SurfaceView.java:582)
                  at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:177)
                  at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944)
                  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2152)
                  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1174)
                  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6241)
                  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:873)
                  at android.view.Choreographer.doCallbacks(Choreographer.java:676)
                  at android.view.Choreographer.doFrame(Choreographer.java:606)
                  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:859)
                  at android.os.Handler.handleCallback(Handler.java:739)
                  at android.os.Handler.dispatchMessage(Handler.java:95)
                  at android.os.Looper.loop(Looper.java:168)
Disconnected from the target VM, address: 'localhost:8602', transport: 'socket'
                      at android.app.ActivityThread.main(ActivityThread.java:5845)
                      at java.lang.reflect.Method.invoke(Native Method)

我的其余代码与上面类似:MainActivity 类

import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity 

private Camera mCamera;
private CameraView mCameraView;
private static final String TAG = "MainActivity";

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);



@Override
protected void onResume()
    super.onResume();


    try
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
            //pyta użytkownika o autoryzację - potrzebne w androidzie => 6.0 tzw. run permission
            ActivityCompat.requestPermissions(this, new String[]android.Manifest.permission.CAMERA, 50);
        else

        mCamera = openFrontFacingCamera();
        mCameraView = new CameraView(this, mCamera);
        setContentView(mCameraView);
     catch (Exception e)
        finish();
    


@Override
protected void onPause()
    if(mCamera != null)
        mCamera.release();
        mCamera = null;
    
    super.onPause();



public Camera openFrontFacingCamera() 



    int cameraCount = 0;
    Camera cam = null;
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    cameraCount = Camera.getNumberOfCameras();
    for (int camIdx = 0; camIdx < cameraCount; camIdx++) 
        Camera.getCameraInfo(camIdx, cameraInfo);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
            try 
                cam = Camera.open(camIdx);
             catch (RuntimeException e) 
                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
            
        
    

    return cam;
    

CameraView 类

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Surface;
import android.view.Display;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;


public class CameraView extends SurfaceView implements SurfaceHolder.Callback


private Camera mCamera;
private View mView;
private WindowManager display;
private Context mContext;
private static final String cameraPreview = "CameraView";
private static final String APP_CLASS = "APP_CLASS";
private static final String Bug = "Bug";

public CameraView(Context context, Camera mCamera) 
    super(context);

    mContext = context;

    this.mCamera = mCamera;
    mCamera.setDisplayOrientation(90);

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);




@Override
public void surfaceCreated(SurfaceHolder holder) 
    try
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
     catch (IOException e) 
        Log.e(cameraPreview, "The failure of the camera settings");
    



@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
    Camera.Parameters params = mCamera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size optionalSize = getOptimalPreviewSize(sizes, width, height);
    params.setPreviewSize(optionalSize.width, optionalSize.height);
    mCamera.setParameters(params);

    boolean isPreviewRunning = true;

    if (isPreviewRunning)
    
        mCamera.stopPreview();
    

    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    width = display.getWidth();
    height = display.getHeight();

    if(display.getRotation() == Surface.ROTATION_0)
    
        parameters.setPreviewSize(height, width);
        mCamera.setDisplayOrientation(90);
    

    if(display.getRotation() == Surface.ROTATION_90)
    
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(0);
    

    if(display.getRotation() == Surface.ROTATION_180)
    
        parameters.setPreviewSize(height, width);
        mCamera.setDisplayOrientation(270);
    

    if(display.getRotation() == Surface.ROTATION_270)
    
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(180);
    

    try
    mCamera.setParameters(parameters);
    previewCamera(holder);
    mCamera.startPreview();
    catch(Exception e)
        Log.e(Bug, "setting Parameters Failed" + e.getLocalizedMessage());

    


public void previewCamera(SurfaceHolder holder)

    try
    
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
        boolean isPreviewRunning = true;
    
    catch(Exception e)
    
        Log.d(APP_CLASS, "Cannot start preview", e);
    


@Override
public void surfaceDestroyed(SurfaceHolder holder) 
    mCamera.release();
    mCamera = null;


private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) 

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio=(double)h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes) 
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff) 
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        
    

    if (optimalSize == null) 
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) 
            if (Math.abs(size.height - targetHeight) < minDiff) 
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            
        
    
    return optimalSize;


 


我会感谢所有可以引导我解决这个问题的建议。

【问题讨论】:

【参考方案1】:

我已经想通了 :) 所以 MainActivity 类现在应该是这样的

    package com.example.arturs.androidmirrorapplicationv2;

import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity 

private CameraView mCameraView;
private Camera mCamera;
private static final String TAG = " => Main Activity: ";

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    mCamera = openFrontFacingCamera();
    setContentView(R.layout.activity_main);




@Override
protected void onResume() 
    super.onResume();

//
//            if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
//                //pyta użytkownika o autoryzację - potrzebne w androidzie => 6.0 tzw. run permission
//                ActivityCompat.requestPermissions(this, new String[]android.Manifest.permission.CAMERA, 50);
//            else

            Log.d(TAG, " -> OnResume");
        try 
            mCamera = openFrontFacingCamera();
            if (mCamera != null) 
                mCameraView = new CameraView(this, mCamera);
                setContentView(mCameraView);
             else 
                Log.d(TAG, " = Camera == NULL");
            

         catch (Exception e) 
            e.printStackTrace();
            finish();
        

        Log.d(TAG, " <- OnResume");




@Override
protected void onPause()
    Log.d(TAG, " -> onPause");
    if(mCamera != null)
        mCamera.release();
        mCamera = null;
    
    super.onPause();
    Log.d(TAG, " <- onPause");



public Camera openFrontFacingCamera() 

//        if (mCamera != null) 
//            mCamera.release();
//            mCamera = null;

    int cameraCount = 0;
    Camera cam = null;
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    cameraCount = Camera.getNumberOfCameras();
    for (int camIdx = 0; camIdx < cameraCount; camIdx++) 
        Camera.getCameraInfo(camIdx, cameraInfo);
        Log.d(TAG, "Camera Info: "+cameraInfo.facing);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
            try 
                return Camera.open(camIdx);
             catch (RuntimeException e) 
                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
            
        
    

    return null;


CameraView 类应该看起来像上面这个,更正

    package com.example.arturs.androidmirrorapplicationv2;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Surface;
import android.view.Display;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;


public class CameraView extends SurfaceView implements SurfaceHolder.Callback


private Camera mCamera;
private View mView;
private WindowManager display;
private Context mContext;
private static final String cameraPreview = "CameraView";
private static final String APP_CLASS = "APP_CLASS";
private static final String Bug = "Bug";

public CameraView(Context context, Camera mCamera) 
    super(context);

    mContext = context;

    this.mCamera = mCamera;
    mCamera.setDisplayOrientation(90);

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);




@Override
public void surfaceCreated(SurfaceHolder holder) 
    try
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
     catch (IOException e) 
        e.printStackTrace();
        Log.e(cameraPreview, "The failure of the camera settings");
    



@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
    Camera.Parameters params = mCamera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size optionalSize = getOptimalPreviewSize(sizes, width, height);
    params.setPreviewSize(optionalSize.width, optionalSize.height);
    mCamera.setParameters(params);


    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();


    if(display.getRotation() == Surface.ROTATION_0)
    
        mCamera.setDisplayOrientation(90);
    

    if(display.getRotation() == Surface.ROTATION_90)
    
        mCamera.setDisplayOrientation(0);
    

    if(display.getRotation() == Surface.ROTATION_180)
    
        mCamera.setDisplayOrientation(270);
    

    if(display.getRotation() == Surface.ROTATION_270)
    
        mCamera.setDisplayOrientation(180);
    

    try
    mCamera.setParameters(parameters);
    previewCamera(holder);
    mCamera.startPreview();
    catch(Exception e)
        e.printStackTrace();
        Log.e(Bug, "setting Parameters Failed" + e.getLocalizedMessage());

    


public void previewCamera(SurfaceHolder holder)

    try
    
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
        boolean isPreviewRunning = true;
    
    catch(Exception e)
    
        e.printStackTrace();
        Log.d(APP_CLASS, "Cannot start preview", e);
    


@Override
public void surfaceDestroyed(SurfaceHolder holder) 
    mCamera.release();
    mCamera = null;


private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) 

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio=(double)h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes) 
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff) 
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        
    

    if (optimalSize == null) 
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) 
            if (Math.abs(size.height - targetHeight) < minDiff) 
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            
        
    
    return optimalSize;



【讨论】:

以上是关于致命异常 - 在 Camera.release() 被称为 HTC ONE M9 之后正在使用相机的主要内容,如果未能解决你的问题,请参考以下文章

在android应用程序中出现致命异常

获取“致命异常 AsyncTask #1”

致命错误:未捕获的异常 PAYPAL

致命异常:UIApplicationInvalidInterfaceOrientation

在发布(dexguard)上构建但在调试中没有出现致命异常

一些 logcat 错误 - 致命异常