概述:
Android framework提供了对各种设备的相机和相机特性的支持, 这让我们在APP中可以捕捉图片和视频. 该文档描述了一个快速简单的方法来创建一个拍照和录像功能, 并概述了一个先进的方法来创建自定义的相机体验.
建议:
在开始让APP使用Android设备的相机之前, 我们应该考虑一些关于APP打算如何使用这个硬件的问题:
相机需求: 对于我们要开发的APP来说, 相机功能真的如此重要以至于放弃在没有相机硬件的设备上的安装吗? 如果是的话, 那么应该在manifest中声明相机需求.
快速图片还是自定义相机: 我们的APP将会如何使用相机呢? 只是需要拍一张快速图片或者视频剪辑? 还是APP本身提供了一种新的使用相机的方式? 如果是前者, 则应该考虑使用已经存在的相机APP. 如果是后者, 则需要自己创建一个相机APP.
储存: APP生成的图片或者视频是打算只是对自己的APP可用, 还是需要分享, 可以被其他的APP访问呢? 在APP被卸载之后, 图片和视频是否还可用呢?
基础:
Android framework支持通过android.hardware.camera2API或者相机Intent抓取图片和视频. 这里是对应的类:
android.hardware.camera2: 这个包是用来控制设备相机的基础API. 它可以用来拍摄照片或者视频.
Camera: 该类是已经过时的控制设备相机的API.
SurfaceView: 该类是用来展示一个直播相机预览给用户的.
MediaRecorder: 该类是用来从相机拍摄视频用的.
Intent: 一个action类型为MediaStore.ACTION_IMAGE_CAPTURE或者MediaStore.ACTION_VIDEO_CAPTURE的intent, 可以用来拍照或者拍视频, 它并不需要直接使用Camera对象.
Manifest声明:
开始开发使用相机的APP之前, 我们应该确定manifest中已经声明了合适的权限来使用相机硬件和相关的功能.
1. Camera Permission: 必选项, 设备相机使用权限.
<uses-permission android:name="android.permission.CAMERA"/>
注意, 如果我们通过一个intent来使用相机, 那么则不需要这个权限.
2. Camera Features – APP也必须声明使用相机功能. 比如:
<uses-feature android:name="android.hardware.camera"/>
增加camerafeatures到我们的manifest会让Google Play阻止APP安装到那些没有相机或者不支持指定的相机功能的设备上. 如果APP可以使用相机或者相机功能但是并不是必须功能, 那么应该通过android:required来指定, 并设置其为false:
<uses-feature android:name="android.hardware.camera" android:required="false" />
3. Storage Permission – 如果APP保存图片或者视频到设备的外部存储(SD卡), 那么必须声明该权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
4. Audio Recording Permission – 如果需要在拍摄的时候录音,那么必须声明这个权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
5. Location Permission – 如果APP需要为图片标记GPS定位信息, 那么必须使用该权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
使用现成的相机APP:
在我们的APP中如果想要快速简单的使用相机拍照或者视频功能的话, 最便捷的方法就是使用一个Intent来调用一个现成的Android相机APP. 一个相机intent可以通过已存在的相机APP来发起拍照或者拍摄视频的需求, 然后将控制权返回给我们的APP. 这一小节将描述如何使用该技术来实现拍照和摄像.
通过intent来调用一个camera的步骤通常是酱婶儿的:
1. 构造一个Camera intent – 创建一个请求一个图片或者视频的Intent, 需要使用这两种类型: MediaStore.ACTION_IMAGE_CAPTURE , 表示想用已经存在的相机APP拍照; MediaStore.ACTION_VIDEO_CAPTURE,表示想用已经存在的相机拍摄视频.
2. 启动Camera Intent – 使用startActivityForResult()方法来执行camera Intent. 然后Camera应用的用户接口将会出现在设备屏幕上, 让用户可以拍照或者视频.
3. 接收Intent结果– 设置一个onActivityResult()方法来接收回调和camera intent返回的数据. 当用户结束拍摄之后, 系统将会调用这个方法.
图片抓取Intent:
使用camera intent来拍照是一种快速的最少代码的可以实现拍照功能的方法. 一个图片抓取intent可以包含下面的额外信息:
l MediaStore.EXTRA_OUTPUT – 这个设置项需要一个Uri对象, 它指定了一个我们想要保存图片的路径和文件名. 这个设置项是可选的, 但是强烈建议使用. 如果没有指定这个值, 那么相机应用将会使用默认文件名保存图片到默认的路径, 这些信息在返回的intent的getData()方法中.
下面的栗子演示了如何构造一个图片抓取intent并执行它. 其中的getOutputMediaFileUri()方法可以在”保存媒体文件”章节找到. 该方法可能在下一篇文章中.
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private Uri fileUri; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // create Intent to take a picture and return control to the calling application Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name // start the image capture Intent startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE); }
当startActivityForResult()方法执行后, 用户可以看到一个camera应用的接口. 当用户拍照之后(或者取消了操作), 用户接口返回到我们自己的APP, 这时候我们必须实现onActivityResult()方法来接收intent的结果, 并继续APP的操作.
视频抓取intent:
使用camera intent抓取视频同样是实现该功能最便捷的方法. 一个视频抓取intent可以支持这些额外的信息:
MediaStore.EXTRA_OUTPUT – 这个设置项需要一个Uri来指定保存视频的路径和文件名. 这个设置项是可选的但是强烈建议使用. 如果没指定这个值的话, 那么Camera应用会将视频保存在默认的路径, 文件名也是默认的, 然后通过Intent.getData()返回数据.
MediaStore.EXTRA_VIDEO_QUALITY – 这个值可以为0, 表示最低质量, 最小文件尺寸. 或者为1表示最高质量和最大文件尺寸.
MediaStore.EXTRA_DURATION_LIMIT- 该值用来限制想要录制的视频的时长, 单位是秒.
MediaStore.EXTRA_SIZE_LIMIT – 该值用来限制录制视频的文件大小, 单位是bytes.
下面的代码演示了如何构造一个视频抓取intent并执行它. 同上, getOutputMediaFileUri()方法在”保存媒体文件”中实现, 这个小节会在下一篇blog中出现.
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; private Uri fileUri; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //create new Intent Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO); // create a file to save the video intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high // start the Video Capture Intent startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE); }
当startActivityForResult()方法执行后, 用户可以看到一个camera应用的接口. 当用户拍摄视频结束之后(或者取消了操作), 用户接口返回到我们自己的APP, 这时候我们必须实现onActivityResult()方法来接收intent的结果, 并继续APP的操作.
接收cameraintent结果:
一旦构造并且执行了一个图片或者视频的camera intent, 我们的APP就必须配置接收intent的结果. 这小节将展示如何从camera intent获取结果, 这样我们的APP就可以处理抓取到的图片或者视频了. 为了接收intent结果, 我们必须在启动intent的activity中重写onActivityResult()方法. 下面的栗子演示了如何重写onActivityResult()方法来从intent中获取结果:
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { // Image captured and saved to fileUri specified in the Intent Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show(); } else if (resultCode == RESULT_CANCELED) { // User cancelled the image capture } else { // Image capture failed, advise user } } if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { // Video captured and saved to fileUri specified in the Intent Toast.makeText(this, "Video saved to:\n" + data.getData(), Toast.LENGTH_LONG).show(); } else if (resultCode == RESULT_CANCELED) { // User cancelled the video capture } else { // Video capture failed, advise user } } }
一旦我们的activity收到了成功的结果, 那么抓取的图片和视频就可以从指定的路径获取到了.
总结:
使用相机是很多APP的基本功能, 多数的即时通讯工具都带有这个功能, 现在几乎所有的APP都有这个功能, 因为我们总是要拍摄一张图片作为头像.
调用系统的拍摄APP很容易, 只需要构造intent然后在处理返回数据就可以了. 逻辑清晰简单. 不多赘述.
参考: https://developer.android.com/guide/topics/media/camera.html