1、检测是否有摄像头
/** Check if this device has a camera */ private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ // this device has a camera return true; } else { // no camera on this device return false; } }
2.3后提供了一个方法可获取摄像头的个数:Camera.getNumberOfCameras()
2、访问获取camera对象
/** A safe way to get an instance of the Camera object. */ 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 }
Caution: Always check for exceptions when using Camera.open()
. Failing to check for exceptions if the camera is in use or does not exist will cause your application to be shut down by the system.
每次使用时都需要检测camera是否可用,否则很可能会让你的应用强制关闭。
在2.3或更高版本中,可以使用Camera.open(int)方法来请求打开哪个摄像头,如果有多前置摄像头,open(1)则是打开前置摄像头,open(0)是打开后置摄像头
3、检查摄像头的特性
Once you obtain access to a camera, you can get further information about its capabilities using the Camera.getParameters()
method and checking the returned Camera.Parameters
object for supported capabilities. When using API Level 9 or higher, use the Camera.getCameraInfo()
to determine if a camera is on the front or back of the device, and the orientation of the image.
4、Creating a preview class
为了让用户可以更好的排出自己想要的照片或视频,用户就需要知道当前摄像头获取到的图片或视频数据,这个时候就需要一个组件来展示让用户预览这些数据。SurfaceView就是这么一个可以预览摄像头当前获取到的图片或视频的组件。
下面的代码演示了如何创建一个基本的预览框,这个预览框可以放在任何的layout内。 这个类实现了SurfaceHolder.Callback
这个接口以用来监听预览组件的创建和销毁。
/** A basic Camera preview class */ 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()); } } }
如果你想给摄像头设置一个特定大小的预览框,需要在surfaceChanged()这个方法内进行修改,当设置尺寸时需要在getSupportedPreviewSizes()
的范围内,而不应该使用setPreviewSize()方法随意设置。
5、Placing preview in a layout
预览图必须要与其他的api共同使用才有效果,无论是拍照还是摄像的预览都需要依赖于activity进行预览展示,下面就是一个最基本的预览图的layout及activity的创建方式,在下面的示例中,FrameLayout 是摄像头预览框的容器。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" 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>
On most devices, the default orientation of the camera preview is landscape. This example layout specifies a horizontal (landscape) layout and the code below fixes the orientation of the application to landscape. For simplicity in rendering a camera preview, you should change your application's preview activity orientation to landscape by adding the following to your manifest.
在大部分的设备中,默认的摄像头预览方向为横屏,下面我们也就直接使用横屏的方式创建Activity
<activity android:name=".CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape"> <!-- configure this activity to use landscape orientation --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
注意:预览不是一定要用横屏,从2.2(API Level8)版本开始,你可以使用setDisplayOrientation()
方法来设置预览图片的方向,为了改变预览的方向,你还需要在surfaceChanged()方法中嫌停止预览,然后更改方向后再重新启动预览。
在你的Activity中,将预览的组件加入FrameLayout中,当Activity处与pause 或者 destroy时,你需要释放Camera的资源以备其他应用使用。
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // 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); } }
6、Capturing pictures
当你创建好了预览组件并且将它显示在屏幕上了,你的应用就已经做好了拍照的准备了。这个时候你需要为你的程序创建Listeners来对Camera进行监控。
为了拍摄下图片,你需要调用Camera.takePicture()
方法,这个方法有3个参数,下面是一个简单的实现方式
private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions: " + e.getMessage()); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } } };
// Add a listener to the Capture button Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, mPicture); } } );
至此Camera的基本用法已结束。