Android相机无法预览,可以拍照

时间:2013-04-23 11:34:07

标签: android camera preview

我正在使用表面视图向用户显示相机预览。这是我启动它的方法:

private void pickCam(){
    if (Camera.getNumberOfCameras() < 1)
        return;

    if (Camera.getNumberOfCameras() == 1)
    {
        CameraInfo cInfo=new CameraInfo();
                Camera.getCameraInfo(0, cInfo);
    camera = Camera.open(0);

    }
    else
        camera = Camera.open(currentCamera);


    Camera.Parameters parameters = camera.getParameters();
    parameters = camera.getParameters();
    parameters.setRotation(90);
    try {

        Camera.Size mCameraSize = null;

        for (Camera.Size size : parameters.getSupportedPreviewSizes()) {


            if (size.width <= surfaceWidth && size.height <= surfaceHeight) {

                if (mCameraSize == null)
                    mCameraSize = size;
                else {

                    int currentArea = mCameraSize.width
                            * mCameraSize.height;
                    int newArea = size.width * size.height;

                    if (newArea > currentArea) {

                        mCameraSize = size;
                    }
                }
            }

        }
        parameters.setPreviewSize(mCameraSize.width, mCameraSize.height);

        camera.setParameters(parameters);

        camera.setDisplayOrientation(90);

        camera.setPreviewDisplay(surfaceHolder);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    camera.startPreview();
}

当用户点击按钮时:

if (camera != null)
camera.takePicture(null, null,this);

此代码适用于Sony Xperia(2个摄像头),但HTC Wildfire和三星Galaxy S +(均为1个摄像头)的预览失败。没有例外,它只是显示没有。我可以在所有这些设备上拍照。

两个设备的pickCamMethod的LogCat输出为空:

04-23 14:25:22.987: I/System.out(5871): PickCamBegin 
04-23 14:25:23.428: I/System.out(5871): PickCamEnd 

我怎样才能让它在所有情况下都有效?

2 个答案:

答案 0 :(得分:2)

在清单文件中添加权限

 <uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />

开发者网站有关于该主题的优秀文档。

http://developer.android.com/guide/topics/media/camera.html

我在开发者网站上使用了代码并制作了一个示例。根据您的需要修改以下内容。

在您的活动中

public class MainActivity extends Activity {

private static final int REQUEST_CODE = 1; 
ImageView imageView;
Button b;
private Camera mCamera;
private CameraPreview mPreview;
private Bitmap bitmap;
private PictureCallback mPicture;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    boolean check =checkCameraHardware(MainActivity.this);
    if(check)
    {
         mCamera = getCameraInstance();

        // mCamera.setDisplayOrientation(90);
         setCameraDisplayOrientation(this,
                 1,  mCamera);//requires min sdk 9
    }
    // Create an instance of Camera
    mPicture = new PictureCallback() {

        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

            File imagesFolder = new File(Environment.getExternalStorageDirectory(), "MyImages");
            if(!imagesFolder.exists())
            imagesFolder.mkdirs();   
            File pictureFile = new File(imagesFolder, "image.jpg");

            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);

                System.out.println("hello");
                fos.write(data);
                fos.close();
            } catch (FileNotFoundException e) {
                Log.d("No File", "File not found: " + e.getMessage());
            } catch (IOException e) {
                //Log.d(TAG, "Error accessing file: " + e.getMessage());
            }
        }
    };

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview);
     b = (Button) findViewById(R.id.button_capture);
     b.setOnClickListener(new OnClickListener()
      {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
                 mCamera.takePicture(null, null, mPicture);
                 Toast.makeText(MainActivity.this, "Called",1000).show();

        }

      });
  }
 public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
         Toast.makeText(this, "Phone has camera", Toast.LENGTH_LONG).show();
        return true;
    } else {
        // no camera on this device
         Toast.makeText(this, "Phone has no camera", Toast.LENGTH_LONG).show();
        return false;
    }
}
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}


@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    mCamera.release();
}
 }

用于预览的CameraPreview类

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;

public CameraPreview(Context context, Camera camera) {
    super(context);
    mCamera = camera;

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

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

public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.

    if (mHolder.getSurface() == null){
      // preview surface does not exist
      return;
    }

    // stop preview before making changes
    try {
        mCamera.stopPreview();
    } catch (Exception e){
      // ignore: tried to stop a non-existent preview
    }

    // set preview size and make any resize, rotate or
    // reformatting changes here

    // start preview with new settings
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}
}

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/>

<Button
android:id="@+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>

答案 1 :(得分:1)

正如您所提到的那些设备HTC Wildfire和Samsung Galaxy S +可能运行在不支持Camera.getNumberOfCameras()的较低版本的Android上。

HTC Wildfire于2010年宣布,支持Android 2.2(API Lv.8)

Samsung Galaxy S+,支持Android 2.3(API Lv.9 / Lv.10)

可在此处找到API级别指南:Android Developers: What is API Level?

因此,您使用的方法Camera.getNumberOfCameras()已添加到API 9中(请参阅Documentation

您可能需要使用Build.VERSION单独处理它们,因此您可以尝试更改pickCam()的第一行:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
// Means the device is using API Lv.9+
// Use the method that can work for Lv.9+
    if (Camera.getNumberOfCameras() < 1)
        return;

    if (Camera.getNumberOfCameras() == 1)
    {
        CameraInfo cInfo=new CameraInfo();
        Camera.getCameraInfo(0, cInfo);
        camera = Camera.open(0);

    }
    else
        camera = Camera.open(currentCamera);
} else {
// Use alternative method that support lower API levels
    camera = Camera.open();
}

Camera.open()是适用于2.2的方法,Camera.open(int)适用于2.3+(请参阅Documentation

如果这对你有用,请告诉我。