调用手机自带的 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,
int[] grantResults) String[] permissions, {
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
的值,来达到缩放图片的效果。