Android调用系统相机、相册功能,适配6.0权限获取以及7.0以后获取URI(兼容多版本)
2018-02-08 09:51
1021 查看
Android中调用系统相机来拍摄照片的代码,如下:1、首先设置Uri获取判断以及相机请求Code[java] view plain copypublic final int TYPE_TAKE_PHOTO = 1;//Uri获取类型判断
public final int CODE_TAKE_PHOTO = 1;//相机RequestCode
2、调起系统相机[java] view plain copyIntent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = getMediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
3、封装获取Uri代码[java] view plain copypublic Uri getMediaFileUri(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "相册名字");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
//创建Media File
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == TYPE_TAKE_PHOTO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return Uri.fromFile(mediaFile);
}
4、相机拍照完毕后获取返回数据,并在页面显示照片[java] view plain copy@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CODE_TAKE_PHOTO:
if (resultCode == RESULT_OK) {
if (data != null) {
if (data.hasExtra("data")) {
Log.i("URI", "data is not null");
Bitmap bitmap = data.getParcelableExtra("data");
imageView.setImageBitmap(bitmap);//imageView即为当前页面需要展示照片的控件,可替换
}
} else {
Log.i("URI", "Data is null");
Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath());
imageView.setImageBitmap(bitmap);//imageView即为当前页面需要展示照片的控件,可替换
}
}
break;
}
}
特殊: 一般情况,以上代码在Android7.0以下,也就是api<24时,运行是没有任何问题的。可是当targetSdkVersion变成24及其以上并且在android7.0(及以上版本)系统运行时,会抛出异常:FileUriExposedException。 权限: 由于已经写过一篇文章对android6.0后权限设置和6.0以前权限设置进行过讲述,在此就不再赘述如何配置权限了,对于6.0后权限设置不了解的,可以看看:通俗易懂,手把手教会你android 6.0后(兼容6.0之前版本)申请危险权限的方法。 Android7.0及以上版本调用系统相机1、为什么会报FileUriExposedException异常 android N以后收回了访问文件的权限,按照android N的要求,若在应用间共享文件,需要发送Content://Uri,而不再是File://Uri,并且需要对此Uri进行临时访问授权。2、解决办法:
使用FileProvider,FileProvider是V4包下的类,继承自ContentProvider。3、使用步骤: ①、首先在清单文件中进行FileProvider注册(与activity同级,四大组件没啥说的):[html] view plain copy<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="项目包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_path" />
</provider>
补充:android:exported="false" 表示对其他应用不可用
android:grantUriPermissions="true" 授予临时权限 ②、在res目录下新建xml文件夹,即res/xml,在xml中新建一个provider_path文件,如下:[html] view plain copy<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path=""/>
</paths>
补充:<paths>下一般常用以下子节点:
<files-path>:Context.getFilesDir()——指向内部存储要共享的目录 <cache-path>:Context.getCacheDir()——指向缓存要共享的目录
<external-path>:Environment.getExternalStorageDirectory()——指向外部存储要共享的目录 <root-path>:尚未发现官方对其的说明,知道的童鞋欢迎补充。根据字面理解,为整个存储的根路径,针对诸如查找不到照片地址的Bug。
name为自定义的名字,path为目录,path=""指的是全部目录|path="."即为当前的根目录 ③、只用更改上面贴出来的getMediaFileUri()方法,因为牵涉多版本调用相机,所以再封装一个适用于7.0以上获取Uri的方法get24MediaFileUri(),代码如下:[java] view plain copy/**
* 版本24以上
*/
public Uri get24MediaFileUri(int type) {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "相册名字");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
//创建Media File
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == TYPE_TAKE_PHOTO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return FileProvider.getUriForFile(this, getPackageName()+".fileprovider", mediaFile);
}
注意:get24MediaFileUri()与getMediaFileUri()唯一的不同为:api24以下,使用的是Uri.fromFile(File)获取的Uri,api24及以上必须使用FileProvider,调用FileProvider.getUriForFile(this, getPackageName()+".fileprovider", File)来获取Uri。 ④、7.0以上调用系统相机,如下:[java] view plain copyIntent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = get24MediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
只是将Uri获取的途径由getMediaFileUri()改为了get24MediaFileUri()。 ⑤、多版本适配1、权限获取的适配,详细请看 通俗易懂,手把手教会你android 6.0后(兼容6.0之前版本)申请危险权限的方法2、在权限获取后,判断SDK版本,然后进行相应操作,如下:[java] view plain copyif (Build.VERSION.SDK_INT >= 24) {
Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = get24MediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
} else {
Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = getMediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
}
⑥、拍照完毕后,获取返回数据显示照片,api24以后,需要转换输入流来获取Bitmap,而输入流的获取需要通过getContentResolvrer.openInputStream()来获取,具体代码如下:[java] view plain copy@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CODE_TAKE_PHOTO:
if (resultCode == RESULT_OK) {
if (data != null) {
if (data.hasExtra("data")) {
Log.i("URI", "data is not null");
Bitmap bitmap = data.getParcelableExtra("data");
imageView.setImageBitmap(bitmap);//imageView即为当前页面需要展示照片的控件,可替换
}
} else {
Log.i("URI", "Data is null");
if (Build.VERSION.SDK_INT >= 24){
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(photoUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
imageView.setImageBitmap(bitmap);
}else {
Bitmap bitmap = BitmapFactory.decodeFile(photoUri.getPath());
imageView.setImageBitmap(bitmap);
}
}
}
break;
}
}
通过以上步骤,即可在多版本系统中调用系统相机并显示了。 系统相册选择图片1、设置相册请求Code[java] view plain copypublic final int CODE_SELECT_IMAGE = 2;//相册RequestCode
2、调用系统相册
[java] view plain copyIntent albumIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(albumIntent, CODE_SELECT_IMAGE);
注意:相册在6.0后会用到访问存储设备这个危险权限,所以也得做权限适配
3、选择图片后,获取返回数据,并显示图片
[java] view plain copy@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CODE_SELECT_IMAGE:
if (resultCode == RESULT_OK) {
selectPic(data);
}
break;
}
}
[java] view plain copy//选择照片
private void selectPic(Intent intent) {
Uri selectImageUri = intent.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectImageUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
imageView.setImageBitmap(BitmapFactory.decodeFile(picturePath));
}
以上即可调用系统相册选择照片,并显示。
public final int CODE_TAKE_PHOTO = 1;//相机RequestCode
2、调起系统相机[java] view plain copyIntent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = getMediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
3、封装获取Uri代码[java] view plain copypublic Uri getMediaFileUri(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "相册名字");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
//创建Media File
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == TYPE_TAKE_PHOTO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return Uri.fromFile(mediaFile);
}
4、相机拍照完毕后获取返回数据,并在页面显示照片[java] view plain copy@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CODE_TAKE_PHOTO:
if (resultCode == RESULT_OK) {
if (data != null) {
if (data.hasExtra("data")) {
Log.i("URI", "data is not null");
Bitmap bitmap = data.getParcelableExtra("data");
imageView.setImageBitmap(bitmap);//imageView即为当前页面需要展示照片的控件,可替换
}
} else {
Log.i("URI", "Data is null");
Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath());
imageView.setImageBitmap(bitmap);//imageView即为当前页面需要展示照片的控件,可替换
}
}
break;
}
}
特殊: 一般情况,以上代码在Android7.0以下,也就是api<24时,运行是没有任何问题的。可是当targetSdkVersion变成24及其以上并且在android7.0(及以上版本)系统运行时,会抛出异常:FileUriExposedException。 权限: 由于已经写过一篇文章对android6.0后权限设置和6.0以前权限设置进行过讲述,在此就不再赘述如何配置权限了,对于6.0后权限设置不了解的,可以看看:通俗易懂,手把手教会你android 6.0后(兼容6.0之前版本)申请危险权限的方法。 Android7.0及以上版本调用系统相机1、为什么会报FileUriExposedException异常 android N以后收回了访问文件的权限,按照android N的要求,若在应用间共享文件,需要发送Content://Uri,而不再是File://Uri,并且需要对此Uri进行临时访问授权。2、解决办法:
使用FileProvider,FileProvider是V4包下的类,继承自ContentProvider。3、使用步骤: ①、首先在清单文件中进行FileProvider注册(与activity同级,四大组件没啥说的):[html] view plain copy<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="项目包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_path" />
</provider>
补充:android:exported="false" 表示对其他应用不可用
android:grantUriPermissions="true" 授予临时权限 ②、在res目录下新建xml文件夹,即res/xml,在xml中新建一个provider_path文件,如下:[html] view plain copy<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path=""/>
</paths>
补充:<paths>下一般常用以下子节点:
<files-path>:Context.getFilesDir()——指向内部存储要共享的目录 <cache-path>:Context.getCacheDir()——指向缓存要共享的目录
<external-path>:Environment.getExternalStorageDirectory()——指向外部存储要共享的目录 <root-path>:尚未发现官方对其的说明,知道的童鞋欢迎补充。根据字面理解,为整个存储的根路径,针对诸如查找不到照片地址的Bug。
name为自定义的名字,path为目录,path=""指的是全部目录|path="."即为当前的根目录 ③、只用更改上面贴出来的getMediaFileUri()方法,因为牵涉多版本调用相机,所以再封装一个适用于7.0以上获取Uri的方法get24MediaFileUri(),代码如下:[java] view plain copy/**
* 版本24以上
*/
public Uri get24MediaFileUri(int type) {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "相册名字");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
//创建Media File
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == TYPE_TAKE_PHOTO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return FileProvider.getUriForFile(this, getPackageName()+".fileprovider", mediaFile);
}
注意:get24MediaFileUri()与getMediaFileUri()唯一的不同为:api24以下,使用的是Uri.fromFile(File)获取的Uri,api24及以上必须使用FileProvider,调用FileProvider.getUriForFile(this, getPackageName()+".fileprovider", File)来获取Uri。 ④、7.0以上调用系统相机,如下:[java] view plain copyIntent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = get24MediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
只是将Uri获取的途径由getMediaFileUri()改为了get24MediaFileUri()。 ⑤、多版本适配1、权限获取的适配,详细请看 通俗易懂,手把手教会你android 6.0后(兼容6.0之前版本)申请危险权限的方法2、在权限获取后,判断SDK版本,然后进行相应操作,如下:[java] view plain copyif (Build.VERSION.SDK_INT >= 24) {
Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = get24MediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
} else {
Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = getMediaFileUri(TYPE_TAKE_PHOTO);
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takeIntent, CODE_TAKE_PHOTO);
}
⑥、拍照完毕后,获取返回数据显示照片,api24以后,需要转换输入流来获取Bitmap,而输入流的获取需要通过getContentResolvrer.openInputStream()来获取,具体代码如下:[java] view plain copy@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CODE_TAKE_PHOTO:
if (resultCode == RESULT_OK) {
if (data != null) {
if (data.hasExtra("data")) {
Log.i("URI", "data is not null");
Bitmap bitmap = data.getParcelableExtra("data");
imageView.setImageBitmap(bitmap);//imageView即为当前页面需要展示照片的控件,可替换
}
} else {
Log.i("URI", "Data is null");
if (Build.VERSION.SDK_INT >= 24){
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(photoUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
imageView.setImageBitmap(bitmap);
}else {
Bitmap bitmap = BitmapFactory.decodeFile(photoUri.getPath());
imageView.setImageBitmap(bitmap);
}
}
}
break;
}
}
通过以上步骤,即可在多版本系统中调用系统相机并显示了。 系统相册选择图片1、设置相册请求Code[java] view plain copypublic final int CODE_SELECT_IMAGE = 2;//相册RequestCode
2、调用系统相册
[java] view plain copyIntent albumIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(albumIntent, CODE_SELECT_IMAGE);
注意:相册在6.0后会用到访问存储设备这个危险权限,所以也得做权限适配
3、选择图片后,获取返回数据,并显示图片
[java] view plain copy@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CODE_SELECT_IMAGE:
if (resultCode == RESULT_OK) {
selectPic(data);
}
break;
}
}
[java] view plain copy//选择照片
private void selectPic(Intent intent) {
Uri selectImageUri = intent.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectImageUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
imageView.setImageBitmap(BitmapFactory.decodeFile(picturePath));
}
以上即可调用系统相册选择照片,并显示。
相关文章推荐
- Android拍照及图片裁剪、调用系统相册(兼容6.0以上权限处理及7.0以上文件管理)
- [置顶] Android 7.0实际开发中调用系统相机和获取相册照片遇到的坑具备向下兼容
- Android 7.0实际开发中调用系统相机和获取相册照片遇到的坑具备向下兼容
- Android手机获取相机权限终极大招(兼容国产手机小米华为魅族以及6.0以下系统)
- Android 调用系统相机拍照(适配7.0)、从图库选择图片、从数据库读取联系人信息、相册图片、扫描文件
- Android调用系统相机以及拉取本地相册的功能实现以及代码分析
- android调用系统相机(通用,完美解决4.0以后版本以及机型的问题)
- 兼容Android 7.0/6.0 启动系统相机/相册 选择图片方法
- 关于Android6.0/7.0权限,以及7.0调用相机和切图的解决办法
- Android调用系统 拍照 相册 适配所有版本 7.0 恢复自动旋转
- Android 拍照以及一些常用的处理,例如将图片显示到相册(包含了安卓系统6.0以上调用相机的处理)
- Android进阶封装之一个类实现兼容Android 6.0权限、适配Android7.0 拍照: 相机与相册上传图片就用我好啦!
- iOS开发:调用系统自带相机以及获取相册照片的功能实现
- Android完美调用系统相机、相册以及裁剪功能
- Android调用系统相册、拍照以及裁剪最简单的实现(兼容7.0)
- 调用系统拍照或相册功能获取裁剪以后的图片
- Android调用系统相册或相机获取图片
- Android打开系统相机、相册,并进行裁剪图片的工具类CameraUtil,以及相册获取图片注意要点。
- Android 调用系统相机拍照保存以及调用系统相册的方法
- Android 调用系统相机拍照保存以及调用系统相册的方法