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

时间:2015-07-21 21:18:04

标签: android camera android-camera

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

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

在两种情况下,“Camera started”都会被记录,我没有例外。

我试图解决这个问题几天,但我找不到原因。 我需要用一个按钮激活它,这样用户就可以选择使用哪个摄像头,并希望在应用程序运行时交换它们。

主要活动:

    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();

        //}
    }
}

预览课程:

    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

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

查看完代码后。问题在于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);

    }    
}