使用按钮初始化相机会导致黑屏,在 onCreate 中初始化工作正常

Initializing Camera with a button results in blank screen, initializing in onCreate works fine

我正在开发一个需要控制相机的应用程序,但我在尝试初始化它时 运行 遇到了问题。

如果我在 onCreate() 中调用函数 SafeOpenCamera() 一切正常,我可以看到相机预览。但是,如果我尝试在按下按钮时调用它,预览区域应该变为空白。

在这两种情况下 "Camera started" 都会被记录下来,我也没有发现异常。

几天来我一直试图解决这个问题,但找不到原因。 我需要用一个按钮激活它,以便用户可以选择要使用的相机,并希望在应用程序运行时交换它们。运行ning。

主要Activity:

    public class MainActivity extends ActionBarActivity {
    private Camera mCamera;
    private CameraPreview mPreview;
    private View mCameraView;
    private Button ulButton;
    private int current_camera=1;

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

        ulButton= (Button) findViewById(R.id.ul_button);
        ulButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // If I try to start the camera with the button, the preview area goeas blank
                boolean opened = safeOpenCamera((FrameLayout) findViewById(R.id.preview_layout), current_camera);
                if (opened == false) {
                    Log.d("Camera", "Error, Camera failed to open");
                } else {
                    Log.d("Camera", "Camera started");
                }
            }
        });

        // If I place the code for opening the camera here, it works fine: //        
        /*boolean opened = safeOpenCamera((FrameLayout) findViewById(R.id.preview_layout), current_camera);
        if (opened == false) {
            Log.d("Camera", "Error, Camera failed to open");
        } else {
            Log.d("Camera", "Camera started");
        }*/

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    private boolean safeOpenCamera(View view, int camera_id){
        Log.d("SafeOpenCamera","starting method");
        boolean qOpened=false;
        releaseCameraAndPreview();
        Log.d("SafeOpenCamera", "camera id " + camera_id);
        mCamera=getCameraInstance(camera_id);
        mCamera.setDisplayOrientation(90);
        mCameraView=view;
        qOpened=(mCamera!=null);
        if(qOpened==true) {
            Log.d("SafeOpenCamera","qOpened true");
            mPreview = new CameraPreview(getBaseContext(), mCamera,mCameraView);
            FrameLayout preview = (FrameLayout) findViewById(R.id.preview_layout);
            preview.addView(mPreview);
            mPreview.startCameraPreview();
            //addItemsOnSpinner2(mPreview.getSizes());

        }
        return qOpened;
    }
    public Camera getCameraInstance(int camera_id){
        Camera c=null;
        try{
            c = Camera.open(camera_id);
        }catch (Exception e){
            e.printStackTrace();
        }
        return c;
    }
    private void releaseCameraAndPreview(){
        if(mCamera!=null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        //if(mPreview!=null){
        //mPreview.destroyDrawingCache();

        //}
    }
}

预览class:

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Context mContext;
    private Camera.Size mPreviewSize;
    private List<Camera.Size> mSupportedPreviewSizes;
    private List<Camera.Size> mSupportedSizes;
    private List<String> mSupportedFlashModes;
    private View mCameraView;

    public CameraPreview(Context context, Camera camera, View cameraView){
        super(context);

        mCameraView=cameraView;
        mContext=context;
        setCamera(camera);

        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void startCameraPreview(){
        try{
            Log.d("Terminal preview","Try set preview");
            mCamera.setPreviewDisplay(mHolder);
            Log.d("Terminal preview", "Try start preview");
            mCamera.startPreview();
        }catch(Exception e){
            Log.d("Terminal preview","exception");
            e.printStackTrace();
        }
    }

    public List<Camera.Size> getSizes(){
        return mCamera.getParameters().getSupportedPictureSizes();
    }

    private void setCamera(Camera camera){
        Log.d("Terminal preview","set camera");
        mCamera=camera;
        mSupportedPreviewSizes=mCamera.getParameters().getSupportedPreviewSizes();
        mSupportedSizes=mCamera.getParameters().getSupportedPictureSizes();
        mSupportedFlashModes=mCamera.getParameters().getSupportedFlashModes();

        Camera.Parameters parameters=mCamera.getParameters();
        Log.d("Terminal preview","set rotation");
        parameters.setRotation(90);

        if(mSupportedFlashModes!=null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)){
            Log.d("Terminal preview","set flash mode");
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);

        }
        Log.d("Terminal preview","set params");
        mCamera.setParameters(parameters);
        Log.d("Terminal preview", "requesting layout...");
        requestLayout();
    }



    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
        Log.d("Terminal preview", "Surface changed");
        if (mHolder.getSurface()==null){
            Log.d("Terminal preview","mHolder null, return");
            return;
        }
        try{
            Log.d("Terminal preview","Try stop preview");
            mCamera.stopPreview();
        }catch (Exception e){
            Log.d("Terminal", "surfaceChanged exception stopPreview");}

        try{
            Camera.Parameters parameters=mCamera.getParameters();

            if (mCamera.getParameters().getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                Log.d("Terminal preview", "set focus mode");
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }

            if(mPreviewSize!=null){
                Camera.Size previewSize=mPreviewSize;
                parameters.setPreviewSize(previewSize.width, previewSize.height);
            }


            mCamera.setParameters(parameters);
            mCamera.startPreview();
        }catch (Exception e){
            Log.d("Terminal","surfaceChanged exception");
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try{
            Log.d("Terminal preview", "try surfaceCreated");
            if(mCamera==null){Log.d("Terminal","mCamera es null");}
            if(holder==null){Log.d("Terminal","holder es null");}
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview(); //
        }catch (IOException e   ){
            Log.d("Terminal preview", "exception surfaceCreated");
            e.printStackTrace();
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d("Terminal preview", "surface destroyed");
        if (mCamera!=null){
            try{
                mCamera.stopPreview();
                mCamera=null;
            }catch (Exception e){Log.d("Terminal preview", "exception surface destroyed");}
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        Log.d("Terminal preview", "onMeassure");
        final int width=resolveSize(getSuggestedMinimumWidth(),widthMeasureSpec);
        final int height=resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
        if (mSupportedPreviewSizes!=null){
            mPreviewSize=getOptimalPreviewSize(mSupportedPreviewSizes,width,height);
        }

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        Log.d("Terminal preview", "onLayout");
        if (changed) {

            final int width=right-left;
            final int height=top-bottom;
            int previewWidth=width;
            int previewHeight=height;

            if(mPreviewSize!=null){
                Display display=((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

                switch (display.getRotation()){
                    case Surface.ROTATION_0:
                        previewWidth=mPreviewSize.height;
                        previewHeight=mPreviewSize.width;
                        mCamera.setDisplayOrientation(90);
                        break;
                    case Surface.ROTATION_90:
                        previewWidth=mPreviewSize.width;
                        previewHeight=mPreviewSize.height;
                        break;
                    case Surface.ROTATION_180:
                        previewWidth=mPreviewSize.height;
                        previewHeight=mPreviewSize.width;
                        break;
                    case Surface.ROTATION_270:
                        previewWidth=mPreviewSize.width;
                        previewHeight=mPreviewSize.height;
                        mCamera.setDisplayOrientation(180);
                        break;
                }
            }
            Log.d("Terminal","t,b,l,r: "+top+" "+bottom+" "+left+" "+right);
            Log.d("Terminal","w: "+width);
            Log.d("Terminal","h: "+height);

            Log.d("Terminal","pw: "+previewWidth);
            Log.d("Terminal","ph: "+previewHeight);

            final int scaledChildHeight=previewHeight*width/previewWidth;

            Log.d("Terminal","h-sh: "+(height-scaledChildHeight));

            mCameraView.layout(0, height - scaledChildHeight, width, height);

        }
    }


    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height){
        Log.d("Terminal preview", "getOptimalPreviewSize");
        Camera.Size optimalSize=null;
        final double ASPECT_TOLERANCE=0.1;
        double targetRatio = (double)height/width;

        for(Camera.Size size: sizes){
            if(size.height!=width) continue;
            double ratio=(double)size.width/size.height;
            if(ratio<=targetRatio+ASPECT_TOLERANCE && ratio >targetRatio-ASPECT_TOLERANCE){
                optimalSize=size;
            }
        }
        if(optimalSize==null){

        }
        return optimalSize;
    }


}

这是我在 onCreate() 中初始化相机时得到的日志(有效的那个)

/SafeOpenCamera﹕ starting method
/SafeOpenCamera﹕ camera id 1
/dalvikvm﹕ Note: class Lcom/lge/mdm/manager/ILGMDMDevicePolicyManager$Stub; has 235 unimplemented (abstract) methods
/SafeOpenCamera﹕ qOpened true
/Terminal preview﹕ set camera
/Terminal preview﹕ set rotation
/Terminal preview﹕ set params
/Terminal preview﹕ requesting layout...
/Terminal preview﹕ Try set preview
/Camera﹕ app passed NULL surface
/Terminal preview﹕ Try start preview
/Camera﹕ Camera started
/Terminal preview﹕ onMeassure
/Terminal preview﹕ getOptimalPreviewSize
/Terminal preview﹕ onMeassure
/Terminal preview﹕ getOptimalPreviewSize
/libEGL﹕ loaded /vendor/lib/egl/libEGL_POWERVR_SGX540_120.so
/libEGL﹕ loaded /vendor/lib/egl/libGLESv1_CM_POWERVR_SGX540_120.so
/libEGL﹕ loaded /vendor/lib/egl/libGLESv2_POWERVR_SGX540_120.so
/OpenGLRenderer﹕ Enabling debug mode 0
/Terminal preview﹕ onLayout
/Terminal﹕ t,b,l,r: 0 300 0 492
/Terminal﹕ w: 492
/Terminal﹕ h: -300
/Terminal﹕ pw: 492
/Terminal﹕ ph: -300
/Terminal﹕ h-sh: 0
/Terminal preview﹕ onLayout
/Terminal preview﹕ try surfaceCreated
/Terminal preview﹕ Surface changed
/Terminal preview﹕ Try stop preview
/Terminal preview﹕ onMeassure
/Terminal preview﹕ getOptimalPreviewSize
/Terminal preview﹕ onMeassure
/Terminal preview﹕ getOptimalPreviewSize
/Terminal preview﹕ onLayout

这是我尝试使用按钮(不起作用的那个)对其进行初始化时得到的日志

/ViewRootImpl﹕ ViewRoot  TouchDown(Absolute) DOWN (105 , 202)
/SafeOpenCamera﹕ starting method
/SafeOpenCamera﹕ camera id 1
/dalvikvm﹕ Note: class Lcom/lge/mdm/manager/ILGMDMDevicePolicyManager$Stub; has 235 unimplemented (abstract) methods
/SafeOpenCamera﹕ qOpened true
/Terminal preview﹕ set camera
/Terminal preview﹕ set rotation
/Terminal preview﹕ set params
/Terminal preview﹕ requesting layout...
/Terminal preview﹕ Try set preview
/Camera﹕ app passed NULL surface
/Terminal preview﹕ Try start preview
/Camera﹕ Camera started
/Terminal preview﹕ onMeassure
/Terminal preview﹕ getOptimalPreviewSize
/Terminal preview﹕ onMeassure
/Terminal preview﹕ getOptimalPreviewSize
/Terminal preview﹕ onLayout
/Terminal﹕ t,b,l,r: 0 300 0 492
/Terminal﹕ w: 492
/Terminal﹕ h: -300
/Terminal﹕ pw: 492
/Terminal﹕ ph: -300
/Terminal﹕ h-sh: 0
/Terminal preview﹕ onLayout
/Terminal preview﹕ try surfaceCreated
/Terminal preview﹕ Surface changed
/Terminal preview﹕ Try stop preview

日志之间的唯一区别似乎是当成功绘制预览时调用 onMeassure() 并加载库:libEGL_POWERVR_SGX540_120.so、libGLESv1_CM_POWERVR_SGX540_120.so 和 libGLESv2_POWERVR_SGX540_120.so,也不知道跟相机有没有关系

在布局中我将预览区域设置为彩色背景,当我尝试使用按钮初始化预览时它变成白色,addView() 是无法正常工作的函数。

源代码可以在这里找到,以防有人有时间查看: dropbox

我不确定你的确切问题是什么,但我遇到过类似的问题。您可以在主布局中插入一个宽度和高度为零的空视图,而不是膨胀 SurfaceView 所在的视图。这样,它会更快。尝试将其插入您的主要 XML 布局中,activity_main

<SurfaceView android:layout_width="0dp" android:layout_height="0dp" />

查看您的代码后。问题出在 onLayout 调用上。

如果您忽略更改后的参数(总是调用您的代码),则会出现堆栈溢出,因为存在无限数量的布局调用。问题在于您如何使用 onLayout 的逻辑。我现在无法深入研究它(花了足够长的时间才到达这里哈哈)。但是删除此功能会导致按钮和非按钮方案都起作用。

因此,我会查看您在何处调用布局代码更改并更改您希望如何调整布局大小的逻辑。但至于这里发布的问题,是下面的代码。删除此函数,您的代码将 运行。那应该让你重新开始! (违规代码如下)

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    if (changed) {

        final int width=right-left;
        final int height=top-bottom;
        int previewWidth=width;
        int previewHeight=height;

        if(mPreviewSize!=null){

            Display display=((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

            switch (display.getRotation()){
                case Surface.ROTATION_0:
                    previewWidth=mPreviewSize.height;
                    previewHeight=mPreviewSize.width;
                    mCamera.setDisplayOrientation(90);
                    break;
                case Surface.ROTATION_90:
                    previewWidth=mPreviewSize.width;
                    previewHeight=mPreviewSize.height;
                    break;
                case Surface.ROTATION_180:
                    previewWidth=mPreviewSize.height;
                    previewHeight=mPreviewSize.width;
                    break;
                case Surface.ROTATION_270:
                    previewWidth=mPreviewSize.width;
                    previewHeight=mPreviewSize.height;
                    mCamera.setDisplayOrientation(180);
                    break;
            }
        }

        final int scaledChildHeight=previewHeight*width/previewWidth;

        mCameraView.layout(0, height - scaledChildHeight, width, height);

    }    
}