我正在开发一款需要控制相机的应用,但是当我尝试初始化它时,我遇到了一个问题。
如果我在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
答案 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);
}
}