调用手机自带的 Camera 应用,并获取图片、视频的简单使用步骤。
本文是基于手机系统已经自带 Camera 应用的前提下,通过发出 Intent 请求 Camera 应用响应拍照和录像。
权限
不管是拍照还是录像,都需要申请使用 camera ;Android M 及以上版本还需要动态申请权限。
AndroidManifest.xml 申请功能
在 AndroidManifest.xml 文件中申请使用 camera 硬件功能。
1 | <manifest ... > |
android:required
表示手机中必须有camera应用软件(如果为false的话,表示不需要存在,通常情况下间接表示当前应用已经实现了camera功能)。- 运行时判断是否支持
camera硬件功能PackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)返回当前手机是否支持camera硬件。
动态申请权限
- 检查是否已经授权
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA); - 申请权限
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); - 确认用户是否授权
1
2
3
4
5
6
7
8
9
10
11
12public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length != 1 ||
grantResults[0] != PackageManager.PERMISSION_GRANTED) {
... // show error dialog.
}
} else {
super.onRequestPermissionsResult(requestCode,
permissions, grantResults);
}
}
拍照
Intent
拍照对应的 Intent 为 MediaStore.ACTION_IMAGE_CAPTURE 。通过 Intent 来启动手机中的 camera 应用:
1 | static final int REQUEST_IMAGE_CAPTURE = 1; |
获取缩略图 thumbnail
手机中的 camera 应用在拍完照后,会返回一个 Intent 数据,其中字段 data 包含了一个 Bitmap 格式的缩略图,通过 ImageView 来显示。
1 |
|
录像
Intent
录像对应的 Intent 为 MediaStore.ACTION_VIDEO_CAPTURE ;
1 | static final int REQUEST_VIDEO_CAPTURE = 1; |
查看视频
手机中的 camera 应用在录像完后,返回的 Intent 中,包含一个录像文件对应的 Uri,根据 Uri 来显示录像,通过 VideoView 来显示。
1 |
|
图片保存及后期处理
外部存储权限
外部存储文件分为:
- 公共文件:
getExternalStoragePublicDirectory()
可以被其他应用自由访问,应用卸载仍然保留;存储路径为/sdcard/或者/storage/emulated0/。 - 私有文件:
getExternalFilesDir(String customDir)
应用私有文件,在应用卸载时会被删除;存储路径为/Android/data/<package_name>/files/customDir。
但不管是那种类型,都需要申请权限:
1 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" |
创建应用私有的图片存储文件:
1 | private File createImageFile() throws IOException { |
应用间文件共享 FileProvider
Android StrictMode 禁止在应用向外部公开 file://URI ,否则应用发出包含文件 URI 的 Intent 时,会抛出 FileUriExposedException 异常。如果需要在应用间共享文件,可以通过 FileProvider 发送 content://URI,并授予 URI 临时访问权限。
在 AndroidManifest.xml 注册 FileProvider :
1 | <provider |
其中需要注意两点:
authorities:在使用FileProvider.getUriForFile返回Uri时,使用的权限需要和这里匹配file_paths:该xml配置文件中需要指定应用需要共享文件的目录,通常为应用私有文件目录1
2
3
4
5
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images"
path="Android/data/com.*.knowledge/files/Pictures" />
</paths>
保存到指定路径
在发起拍照的 Intent 中,将在外部存储空间存储图片的绝对路径转换为 Uri 后,写入 MediaStore.EXTRA_OUTPUT 字段。
1 | private void dispatchTakePictureIntent() { |
如果指定了保存路径
MediaStore.EXTRA_OUTPUT,返回的Intent将不再带有Bitmap缩略图。如果想显示图片,需要通过指定的保存路径来获取。
添加到媒体数据库
如果新增了多媒体文件,通过发送广播 Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 来通知系统扫描这个文件,并加入多媒体数据库中。
1 | private void addPicToMediaDB() { |
如果图片存储路径为
getExternalFilesDir,媒体扫描时无法扫描这些APP私有的目录;也就是说,如果希望能添加到多媒体数据中,不能将图片存储到getExternalFilesDir目录下。
缩放图片
如果按照 ImageView 宽高来缩放图片时,必须要在 xml 中先指定 ImageView 的宽高,不能设置为 wrap_content ,否则获取到的宽高为 0 。
通过 BitmapFactory.Options 先获取原始图片的大小,再根据 ImageView 的宽高来计算比率,设置到 BitmapFactory.Options.inSampleSize 中。
1 | private void scalePic() { |
小结
权限
不管是录像还是拍照,使用前需要定义使用 camera 硬件,并动态申请权限。
拍照和录像的 Intent
- 拍照:
MediaStore.ACTION_IMAGE_CAPTURE - 录像:
MediaStore.ACTION_VIDEO_CAPTURE
返回数据
- 拍照:返回
Bitmap,数据在Intent.Bundle中的data字段 - 录像:返回
Uri,数据在Intent.getData
保存文件及分享
通过 getExternalFilesDir 获取应用的私有文件目录,通过 FileProvider 共享给其他应用。
缩放图片因子
通过设置 BitmapFactory.Options.inSampleSize 的值,来达到缩放图片的效果。