android——创建camera应用(译)

   只是选择相机部分来翻译。下面是主要内容

  有些开发者可能需要Camera的接口,来定制自己程序的外观和特殊功能。创建自定义的Camera界面比使用using an Intent需要编写更多的代码,但是它能提供更好的体验给用户。

创建自定义camera界面的一般步骤,可以参考一下步骤:

  1. 检测和连接相机—检测camera是否存在和请求连接
  2. 创建预览类—创建Preview,它继承SurfaceView和实现了SurfaceHolder接口。这个类可以预览相机中动态的画面。
  3. 构造预览的布局一旦你拥有了Preview类,就需要创建一个View布局。布局中放入Preview和你想要的其他UI。
  4. 给拍照设置监听器—连接监听器去启动拍照,来响应用户的动作,例如按下按钮。
  5. 拍照和保存文件—编写代码实现拍照和保存输出。
  6. 释放相机—使用camera后,程序必须合理的释放它,给其他程序使用。

  相机硬件上一个共享的资源,必须被安全的管理,所以当使用相机时,你的程序不能和其他程序冲突。下面部分讲述怎样检测相机硬件,怎样连接相机,怎样拍照和当不使用时怎样释放相机。

  注意:当应用程序不使用相机时,记得通过调用Camera.release()来释放Camera对象。如果没有合理释放camera,后面全部对camera的连接都会失败,将导致你的或其他程序被关闭。

检测相机硬件

   如果你的程序没有在manifest声明需要相机,你应该在代码运行时检测相机是否可用。使用PackageManage.hasSystemFeature()方法来执行检测,下面是例子:

 1 /** Check if this device has a camera */
 2 private boolean checkCameraHardware(Context context) {
 3     if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
 4         // this device has a camera
 5         return true;
 6     } else {
 7         // no camera on this device
 8         return false;
 9     }
10 }

   android设备可以用多个相机,例如后置相机用来拍照,前置相机用来摄像。Aandroid 2.3(API Level 9)和以后版本,你可以使用Camera.getNumberOfCameras()方法来检测相机的数目。

连接相机

  如果你已经确定程序运行的设备上有相机,你必须请求连接来获取一个Camera实例(除非你使用intent来连接相机)。

  使用Camera.opern()连接主要的相机,要确保捕获异常,就像下面的代码:

 1 /** A safe way to get an instance of the Camera object. */
 2 public static Camera getCameraInstance(){
 3     Camera c = null;
 4     try {
 5         c = Camera.open(); // attempt to get a Camera instance
 6     }
 7     catch (Exception e){
 8         // Camera is not available (in use or does not exist)
 9     }
10     return c; // returns null if camera is unavailable
11 }

  注意:当使用Camera.open()时,总是要检查异常。如果不检查,当相机正在被使用或者不存在时,你的程序将会被系统关闭。

  运行Android 2.3(API Level 9)或以上版本的设备,你可以使用Camera.open(int)连接特定的相机。上面的代码将会连接设备的第一个后置相机,如果存在多个相机。

检查相机特征

  一旦你获取到相机的连接,你可以使用Camera.getParameters()方法获取有关它的功能的更多信息,检查返回的Camera.Parameters对象来知道相机支持的功能。

  当使用API Level 9或以上的版本,使用Camera.getCameraInfo()确定相机是前置还是后置,图片的方向。

创建预览类

  为了用户能有效地拍照,他们必须能够看到设备相机看到的。一个相机预览类是一个SurfaceView,它能展示来自相机的动态的图像数据,所以用户可以能拍摄到照片。

  下面的例子展示了如何创建一个基本的相机预览类,它被包含在一个View布局中。这个类实现了SurfaceHolder.Callback接口,为了能捕捉到创建和销毁这个类时的回调事件。

 1 /** A basic Camera preview class */
 2 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
 3     private SurfaceHolder mHolder;
 4     private Camera mCamera;
 5 
 6     public CameraPreview(Context context, Camera camera) {
 7         super(context);
 8         mCamera = camera;
 9 
10         // Install a SurfaceHolder.Callback so we get notified when the
11         // underlying surface is created and destroyed.
12         mHolder = getHolder();
13         mHolder.addCallback(this);
14         // deprecated setting, but required on Android versions prior to 3.0
15         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
16     }
17 
18     public void surfaceCreated(SurfaceHolder holder) {
19         // The Surface has been created, now tell the camera where to draw the preview.
20         try {
21             mCamera.setPreviewDisplay(holder);
22             mCamera.startPreview();
23         } catch (IOException e) {
24             Log.d(TAG, "Error setting camera preview: " + e.getMessage());
25         }
26     }
27 
28     public void surfaceDestroyed(SurfaceHolder holder) {
29         // empty. Take care of releasing the Camera preview in your activity.
30     }
31 
32     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
33         // If your preview can change or rotate, take care of those events here.
34         // Make sure to stop the preview before resizing or reformatting it.
35 
36         if (mHolder.getSurface() == null){
37           // preview surface does not exist
38           return;
39         }
40 
41         // stop preview before making changes
42         try {
43             mCamera.stopPreview();
44         } catch (Exception e){
45           // ignore: tried to stop a non-existent preview
46         }
47 
48         // set preview size and make any resize, rotate or
49         // reformatting changes here
50 
51         // start preview with new settings
52         try {
53             mCamera.setPreviewDisplay(mHolder);
54             mCamera.startPreview();
55 
56         } catch (Exception e){
57             Log.d(TAG, "Error starting camera preview: " + e.getMessage());
58         }
59     }
60 }

   如果你想为相机预览类设定一个特定的大小,在上面的surfaceChaned()方法中设定。当设定大小时,你必须从getSupportedPreviewSizes()获取数值。不要随意设定一个值。

放置preview入一个布局中

  相机预览类,如同上面展示的,它必须被放置进Activity的布局中,这样其他UI可以控制拍照。下面一节展示了如何为这个preview创建一个基本的布局和Activity。

  下面的布局代码提供了一个非常基本的view来展示相机预览类。在这个例子中,FrameLayout元素就是相机预览类的容器。使用这个布局类型,可以把另外的图片信息或者控制覆盖在动态相机预览图像上。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:orientation="horizontal"
 4     android:layout_width="fill_parent"
 5     android:layout_height="fill_parent"
 6     >
 7   <FrameLayout
 8     android:id="@+id/camera_preview"
 9     android:layout_width="fill_parent"
10     android:layout_height="fill_parent"
11     android:layout_weight="1"
12     />
13 
14   <Button
15     android:id="@+id/button_capture"
16     android:text="Capture"
17     android:layout_width="wrap_content"
18     android:layout_height="wrap_content"
19     android:layout_gravity="center"
20     />
21 </LinearLayout>

  在大多数设备中,相机预览默认的方向是横向的。这个例子设定了水平布局,下面的代码中修改了应用程序的方向为横向。为了使相机预览类渲染简单,你应该应该把照着下面在manifest中把应用程序预览所在的ctivity为横向。

 1 <activity android:name=".CameraActivity"
 2           android:label="@string/app_name"
 3 
 4           android:screenOrientation="landscape">
 5           <!-- configure this activity to use landscape orientation -->
 6 
 7           <intent-filter>
 8         <action android:name="android.intent.action.MAIN" />
 9         <category android:name="android.intent.category.LAUNCHER" />
10     </intent-filter>
11 </activity>

  注意:相机预览不一定要是横向的。从android 2.2(API 8)开始,你可以使用setDisplayOrientation()方法去旋转预览的图像。当用户改变了手机方向,如果要调整预览的方向,可以在预览类的surfaceChanged()方法中,先使用Camer.stopPreview()停止预览,然后改变方向,最后再使用Camera.startPreview()打开预览.

  在你相机视图所在的activity中,下面的例子中,添加了预览类到FrameLayout元素中。这个activity必须确保当它被暂停(paused)或者关闭时,要释放相机。下面的例子,展示了如何向activity添加预览类(在创建预览类一节提到的)。

 1 public class CameraActivity extends Activity {
 2 
 3     private Camera mCamera;
 4     private CameraPreview mPreview;
 5 
 6     @Override
 7     public void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.main);
10 
11         // Create an instance of Camera
12         mCamera = getCameraInstance();
13 
14         // Create our Preview view and set it as the content of our activity.
15         mPreview = new CameraPreview(this, mCamera);
16         FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
17         preview.addView(mPreview);
18     }
19 }

 注意:getCameraInstance()方法,是在连接相机一节的。

拍照

  一旦你构建了预览类(preview)和一个展示它的视图布局,你将要在你的应用程序中开始编写拍照了。你必须设置监听器给你的UI去响应用户的拍照动作。
为了获取照片,使用Camera.takePicture()方法。这个方法需要三个参数,它们从camera中获取数据。为了获取JPEG格式的数据,你必须实现一个Camera.PictureCallback接口来获取图像数据,并且写入一个文件中。

  下面的代码展示了一个基本的实现,如何保存来自camera的图像。

 1 private PictureCallback mPicture = new PictureCallback() {
 2 
 3     @Override
 4     public void onPictureTaken(byte[] data, Camera camera) {
 5 
 6         File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
 7         if (pictureFile == null){
 8             Log.d(TAG, "Error creating media file, check storage permissions: " +
 9                 e.getMessage());
10             return;
11         }
12 
13         try {
14             FileOutputStream fos = new FileOutputStream(pictureFile);
15             fos.write(data);
16             fos.close();
17         } catch (FileNotFoundException e) {
18             Log.d(TAG, "File not found: " + e.getMessage());
19         } catch (IOException e) {
20             Log.d(TAG, "Error accessing file: " + e.getMessage());
21         }
22     }
23 };

 

   

  通过Camera.takePicture()触发拍照。下面的例子展示了如何通过button的View.OnClickListener调用此方法。

 1 // Add a listener to the Capture button
 2 Button captureButton = (Button) findViewById(id.button_capture);
 3 captureButton.setOnClickListener(
 4     new View.OnClickListener() {
 5         @Override
 6         public void onClick(View v) {
 7             // get an image from the camera
 8             mCamera.takePicture(null, null, mPicture);
 9         }
10     }
11 );

 

  提示:mPicture成员变量来自上面的例子。
  注意:记得当你的应用程序停止使用Camera对象时通过Camera.release()释放它。如何释放camera的细节,情况释放相机一节。

释放相机

  相机作用一种资源,被设备中的多个应用程序共享。你的应用程序在获取Camera实例后可以使用它,当你的程序停止使用它时,或者一旦你的程序暂停(Activity.onPause()),你必须特别注意去释放它。如果你的程序没有适当的释放它,所有后续对它的连接请求,都会导致你的程序或者其他程序都会被关闭。

  使用Camera.release()方法释放一个Camera对象的实例,下面是例子。

 1 public class CameraActivity extends Activity {
 2     private Camera mCamera;
 3     private SurfaceView mPreview;
 4 
 5     ...
 6 
 7     @Override
 8     protected void onPause() {
 9         super.onPause();
10         releaseCamera();              // release the camera immediately on pause event
11     }
12 
13     private void releaseCamera(){
14         if (mCamera != null){
15             mCamera.release();        // release the camera for other applications
16             mCamera = null;
17         }
18     }
19 }

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

转载于:https://www.cnblogs.com/dann/p/3315721.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值