一、 打开系统相机:
1. 直接用如下代码就可以打开系统相机,不需要申请任何权限。
Intent intent =new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 表示跳转至相机的拍照界面
Intent intent =new Intent(MediaStore.ACTION_VIDEO_CAPTURE); // 表示跳转至相机的录视频界面
startActivity(intent);
总结:
1). 不管是拍照和录像,预览阶段都没有问题。但是拍照或录像的数据获取不到。
2). 录像时不能手动或自动结束,只可以手动暂停或退出。
二、获取拍照或录像后的数据:
1. 实现方法:
重写Activity的方法:protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
使用startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);//启动相机
2. 对于拍照情况:
在onActivityResult()方法中,缩略图信息是储存在返回的intent中的Bundle中的,对应Bundle中的键为“data”,因此从Intent中取出Bundle再根据data取出来Bitmap即可。代码如下:
Bundle extras = data.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
LogUtil.d(TAG, "onActivityResult() --- bitmap.getWidth = " + bitmap.getWidth()
+" bitmap.getHeight = " + bitmap.getHeight());
imageView.setImageBitmap(bitmap);
3. 对于录像的情况:
在跳转时还应该设置:
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10); // 设置视频录制的最长时间
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); // MediaStore.EXTRA_VIDEO_QUALITY 表示录制视频的质量,从 0-1,越大表示质量越好,同时视频也越大
startActivityForResult(intent, REQUEST_CODE_RECORD_VIDEO);//启动相机
在onActivityResult()方法中,视频的保存路径是从Intent中Uri中返回的。代码如下:
Uri uri = data.getData(); // 视频的保存路径
if (null != uri) {
LogUtil.i(TAG, "videoPath = " + uri.toString());
}else {
LogUtil.e(TAG, "onActivityResult() --- uir == null");
}
总结:
1.返回的图片失真很严重,原因是现在相机的像素都很大,随便一张图片都上M,而Android系统分配给每个应用的最大内存是16M,如果直接将图片通过内存方式返回给调用者会占用过大的内存,因此这里得到的是一个处理后的缩略图。
- 录像时返回视频的保存地址,由于没有设置保存的路径,所以返回视频路径的是系统默认保存路径。
三、将拍照或录像数据保存在指定位置
1. 创建指定的文件:
需要申请读写文件的权限,动态申请权限这里就不写了。
private File createImageFile(String filePath) {
if (TextUtils.isEmpty(filePath)) {
return null;
}
File file = new File(filePath);
File dirFile = file.getParentFile();
if (null != dirFile) {
if (!dirFile.exists()) {
dirFile.mkdirs();
}
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
file = null;
}
return file;
}
2.调用相机进行拍照:
private void callSysCameraAppToTakePhoto() {
// 拍照
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aDemoCamera/testSys.jpg";
File imageFile = createImageFile(filePath);
Uri imageUri;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 表示跳转至相机的拍照界面
if (intent.resolveActivity(getPackageManager()) != null) {//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退
if (null != imageFile) {
/*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/
imageUri = Uri.fromFile(imageFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 表示录制完后保存的录制,如果不写,则会保存到默认的路径,在onActivityResult()的回调,通过intent.getData中返回保存的路径
startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);//启动相机
} else {
LogUtil.e(TAG, "callSysCameraAppToTakePhoto() -- error: imageFile == null");
}
} else {
LogUtil.e(TAG, "callSysCameraAppToTakePhoto() -- error: open camera App failed");
}
}
3.调用相机进行录像:
private void callSysCameraAppToRecordVideo() {
// 录像
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aDemoCamera/testSys.mp4";
File videoFile = createImageFile(filePath);
Uri videoUri = null;
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); // 表示跳转至相机的录视频界面
if (intent.resolveActivity(getPackageManager()) != null) {//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退
if (null != videoFile) {
/*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/
videoUri = Uri.fromFile(videoFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri); // 表示录制完后保存的录制,如果不写,则会保存到默认的路径,在onActivityResult()的回调,通过intent.getData中返回保存的路径
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10); // 设置视频录制的最长时间
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); // MediaStore.EXTRA_VIDEO_QUALITY 表示录制视频的质量,从 0-1,越大表示质量越好,同时视频也越大
startActivityForResult(intent, REQUEST_CODE_RECORD_VIDEO);//启动相机
} else {
LogUtil.e(TAG, "callSysCameraAppToRecordVideo() -- error: 222222222");
}
}
}
总结:
- 如上面代码就可以调用系统相机进行拍照或录像,并把数据保存在自己指定的路径中。
- 问题:只支持Android 7 以下的系统,Android7及以上系统需要FileProvider来实现APP文件的分享。
四、兼容Android7
1. 在AndroidManifest.xml中添加provider标签,与Activity标签平行:
2.在res文件夹中 新建xml文件夹,然后新建xml文件file_paths.xml,内容如下:
在在paths节点内部支持以下几个子节点,分别为:
因为之前数据保存在Environment.getExternalStorageDirectory().getAbsolutePath() + "/aDemoCamera/testSys.mp4";中,所以我把external-path节点的path设置为 path="aDemoCamera"。
关于FileProvider内容这里不再多说。
3.发起拍照或录像:
private final String AUTH_FILE_PROVIDER = "com.cakes.democamera.fileprovider";
private void callSysCameraAppToTakePhoto() {
// 拍照
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aDemoCamera/testSys.jpg";
File imageFile = createImageFile(filePath);
Uri imageUri;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 表示跳转至相机的拍照界面
if (intent.resolveActivity(getPackageManager()) != null) {//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退
if (null != imageFile) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
/* Android7及以上需要使用FileProvider */
imageUri = FileProvider.getUriForFile(this, AUTH_FILE_PROVIDER, imageFile);
} else {
/*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/
imageUri = Uri.fromFile(imageFile);
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 表示录制完后保存的录制,如果不写,则会保存到默认的路径,在onActivityResult()的回调,通过intent.getData中返回保存的路径
startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);//启动相机
} else {
LogUtil.e(TAG, "callSysCameraAppToTakePhoto() -- error: imageFile == null");
}
} else {
LogUtil.e(TAG, "callSysCameraAppToTakePhoto() -- error: open camera App failed");
}
}
这里代码就主要加了如下一句。录像也是如此。
/* Android7及以上需要使用FileProvider */
imageUri = FileProvider.getUriForFile(this, AUTH_FILE_PROVIDER, imageFile);
总结:
之前写代码时还是觉得挺简单的,但是把知识整理写下来才发现还是有挺多干货的。这应该就是所谓的眼高手低吧.....以后还是要坚持写点东西啊,加油!