targetSdk27 FileProvider 摄像和照相
27
- 相机
- 严格模式解决办法
- 摄像
- 官方推荐 - FileProvider
- 1. 缘由[(转载)](https://blog.csdn.net/wxz1179503422/article/details/84874171)
- 2. 配置 FileProvider
- 2.1 AndroidManifest内配置FileProvider
- 2.2 可访问路径配置
- 分析路径什么用途?
- 其他路径
- 配置的标签参照FileProvider里面的TAG配置
- 3. 访问 FileProvider
- 4. 拓展:获取图片方式
- 4.1 通过绝对路径获取图片
- 4.2 通过Uri获取资源流
- 4.3 通过cursor获取图片
相机
以下,调用相机的代码出自开源项目 SelectImgAsWechath 。
添加权限:
<!--拍照--><uses-permission android:name="android.permission.CAMERA" /><!--写入SD卡的权限:如果你希望保存相机拍照后的照片--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!--读取SD卡的权限:打开相册选取图片所必须的权限--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!--网络--><uses-permission android:name="android.permission.INTERNET"/><!-- 在SDCard中创建与删除文件权限 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permission android:name="android.permission.RECORD_AUDIO" />
调用:
public void takePicture(Activity activity, int requestCode) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (intent.resolveActivity(activity.getPackageManager()) != null) {if (existSDCard()) {takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");} else {takeImageFile = Environment.getDataDirectory();}Log.i(TAG, "takeImageFile ===" + takeImageFile);takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");Log.i(TAG, "createFile ===" + takeImageFile);if (takeImageFile != null) {Uri uri = Uri.parse("file://" + takeImageFile.getAbsolutePath());Log.i(TAG, "uri ===" + uri);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}}activity.startActivityForResult(intent, requestCode);}
发生异常:
在使用照相机或者摄像机的时候出现异常(targetSdkVersion 27):
io.reactivex.exceptions.OnErrorNotImplementedException: file:///storage/emulated/0/DCIM/camera/IMG_20200526_110146.jpg exposed beyond app through ClipData.Item.getUri()at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:77)at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:67)
经百度:
参考地址:解决exposed beyond app through ClipData.Item.getUri() 错误
7.0后的版本:
不再允许在app之间,使用file://的方式传递File,否则会抛出FileUriExposedException异常
FileUriExposedException:
应用程序将file://Uri 暴露给另一个应用程序时引发的异常。不鼓励这种曝光,因为接收应用可能无法访问共享路径。
严格模式解决办法
项目中的解决办法是
在onCreate的时候,添加如下代码:
// android 7.0系统解决拍照的问题StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();StrictMode.setVmPolicy(builder.build());builder.detectFileUriExposure();
StrictMode 严格模式应用:https://www.jianshu.com/p/b80c58677892
Android 2.3提供一个称为严苛模式(StrictMode)的调试特性,Google称该特性已经使数百个Android上的Google应用程序受益。那它都做什么呢?它将报告与线程及虚拟机相关的策略违例。一旦检测到策略违例(policy violation),你将获得警告,其包含了一个栈trace显示你的应用在何处发生违例。你可以强制用警告代替崩溃(crash),也可以仅将警告计入日志,让你的应用继续执行。
虽然官方官方不是这么推荐滴,但是存在即合理?
摄像
通过这段代码,摄像机也可以这么搞:
private void takenVedio() {// 表示跳转至相机的录视频界面Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);// MediaStore.EXTRA_VIDEO_QUALITY 表示录制视频的质量,从 0-1,越大表示质量越好,同时视频也越大intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 30);// 调用前置摄像头intent.putExtra("android.intent.extras.CAMERA_FACING", 1);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (intent.resolveActivity(getPackageManager()) != null) {File file;if (existSDCard()) {file = new File(Environment.getExternalStorageDirectory(), "/DCIM/audio/");} else {file = Environment.getDataDirectory();}Log.i(TAG, "file ===" + file);file = createFile(file, "VIDEO_", ".mp4");Log.i(TAG, "file ===" + file);if (file != null) {Uri uri = Uri.parse("file://" + file.getAbsolutePath());Log.i(TAG, "uri ===" + uri);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}}startActivityForResult(intent, REQUEST_CODE_RECORD_VIDEO);}
官方推荐 - FileProvider
1. 缘由(转载)
2. 配置 FileProvider
2.1 AndroidManifest内配置FileProvider
注意:provider是4大组件,需要放置application中哦
<providerandroid:name="android.support.v4.content.FileProvider"android:authorities="${applicationId}.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/install" /></provider>
2.2 可访问路径配置
位置:
install.mxl :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-pathname="DCIM"path="DCIM/camerademo" /><!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/目录--><external-pathname="external_storage_root"path="." /><external-pathname="Pictures"path="Pictures/camerademo" /><!--代表app 私有的存储区域 Context.getFilesDir()目录下的images目录 /data/user/0/com.hm.camerademo/files/images--><files-pathname="private_files"path="images" /><!--代表app 私有的存储区域 Context.getCacheDir()目录下的images目录 /data/user/0/com.hm.camerademo/cache/images--><cache-pathname="private_cache"path="images" /><!--代表app 外部存储区域根目录下的文件 Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)目录下的Pictures目录--><!--/storage/emulated/0/Android/data/com.xx.xxxxxx/files/Pictures--><external-files-pathname="external_files"path="Pictures" /><!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的images目录--><!--/storage/emulated/0/Android/data/com.xx.xxxxxx/cache/images--><external-cache-pathname="external_cache"path="." /></paths>
分析路径什么用途?
当调用Environment.getExternalStorageDirectory()获取,外部存储根目录时,获取的路径是:
/storage/emulated/0
打印2.3中
photoUri = FileProvider.getUriForFile(this,getPackageName() + ".fileprovider",takeImageFile);
photoUri 的值:
content://com.yoshin.company.blogdemo.fileprovider/external_storage_root/DCIM/camera/IMG_20200526_203123.jpg
此时外部存储根目录在Uri中显示为 “external_storage_root”
所以:
<external-pathname="external_storage_root"path="." />
中,name代表uri中显示名称,path是绝对路径。
其他路径
<external-pathname="DCIM"path="DCIM/camerademo" />
我们知道获取DCIM的路径代码是:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile()
打印出的路径是:
/storage/emulated/0/DCIM
所以,我们可以知道替换
takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");
为
takeImageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile(), "/DCIM/camera/");
时,会打印出:
content://com.yoshin.company.blogdemo.fileprovider/external_storage_root/DCIM/DCIM/camera/IMG_20200526_203123.jpg
通过:
<external-pathname="DCIM"path="DCIM/camerademo" />
我们知道,Uri中要显示"DCIM",绝对路径必须是 path=“DCIM/camerademo”,修改代码:
takeImageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile(), "/camerademo/");
此时,打印出来的Uri即是:
content://com.yoshin.company.blogdemo.fileprovider/DCIM/IMG_20200526_204125.jpg
懂了吗?
当我们代码中使用的绝对路径,(如 “DCIM/camerademo”)匹配到了install.mxl中设置到的path字段的内容(path=“DCIM/camerademo”),Uri中显示路径就会被对应的name字段内容替代了。
配置的标签参照FileProvider里面的TAG配置
3. 访问 FileProvider
public void takePicture(Activity activity, int requestCode) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION| Intent.FLAG_ACTIVITY_CLEAR_TOP);if (existSDCard()) {takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");} else {takeImageFile = Environment.getDataDirectory();}takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");photoUri = FileProvider.getUriForFile(this,getPackageName() + ".fileprovider",takeImageFile);intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);activity.startActivityForResult(intent, requestCode);}
4. 拓展:获取图片方式
4.1 通过绝对路径获取图片
image.setImageBitmap(BitmapFactory.decodeFile(takeImageFile.getAbsolutePath()));
4.2 通过Uri获取资源流
Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(photoUri));} catch (FileNotFoundException e) {e.printStackTrace();}image2.setImageBitmap(bitmap);
4.3 通过cursor获取图片
嘿嘿嘿,这是错误示范,引以为戒
Cursor cursor = getContentResolver().query(photoUri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);if (cursor != null) {if (cursor.getColumnCount() > 0) {if (cursor.moveToFirst()) {int index = cursor.getColumnIndex(MediaStore.Images.Media.DATA);if (index > -1) {path = cursor.getString(index);} else {LogUtils.e(TAG, "cursor index -1");}}}cursor.close();}
通过Uri和selection来获取真实路径
Android系统提供了MediaScanner,MediaProvider,MediaStore等接口,并且提供了一套数据库表格,通过Content Provider的方式提供给用户。当手机开机或者有SD卡插拔等事件发生时,系统将会自动扫描SD卡和手机内存上的媒体文件,如audio,video,图片等,将相应的信息放到定义好的数据库表格中。
在这个程序中,我们不需要关心如何去扫描手机中的文件,只要了解如何查询和使用这些信息就可以了。
MediaStore中定义了一系列的数据表格,通过ContentResolver提供的查询接口,我们可以得到各种需要的信息。
EXTERNAL_CONTENT_URI 为查询外置内存卡的,INTERNAL_CONTENT_URI为内置内存卡。
MediaStore.Audio获取音频信息的类
MediaStore.Images获取图片信息
MediaStore.Video获取视频信息
为什么是错误示范呢?
因为 getContentResolver().query(photoUri, new String[]{MediaStore.Images.Media.DATA}, null, null, null); 查询不到任何图片信息,这和Uri有关系,因为我们的Uri不是目标文件的绝对路径,所以查询不到任何东西。
至于Uri怎么设置成绝对路径(试了试,都没有成功),
我自己拼了个Uri
Uri uri = new Uri.Builder().scheme("content").authority(BuildConfig.APPLICATION_ID+".fileprovider").path("/DCIM/camerademo/IMG_20200527_093044.jpg").build();
打印:
uri ===content://com.yoshin.company.blogdemo.fileprovider/DCIM/camerademo/IMG_20200527_093044.jpg
替换photoUri去查询,并不好用,查询出0条信息。
再试下,还是不行~~~~
Uri uri = new Uri.Builder().scheme("content").authority(BuildConfig.APPLICATION_ID+".fileprovider").path("/storage/emulated/0/DCIM/camerademo/IMG_20200527_093044.jpg").build();
崩溃了。
通过cursor获取图片,不太懂怎么弄的,记录一下。欢迎大神留言。感谢。
推荐Github开源项目 SelectImgAsWechath :https://github.com/SCCXYS/SelectImgAsWechat
参考地址:Android FileProvider详细解析和踩坑指南
targetSdk27 FileProvider 摄像和照相相关推荐
- 安卓个人中心头像模块(从相册选择和照相功能,适配7.0)
** 开篇: ** 1.讲解Intent中的四个重要属性--Action.Data.Category.Extras 2.关于 Android 7.0 适配中 FileProvider 部分的总结 3. ...
- 什么是婚礼一条龙服务及一站式服务
现代的婚礼市场是一个琳琅满目及鱼龙混杂的市场,面对庆典公司.礼仪服务公司.花坊.花店各种服务的店面,新人如何去选择,可以说是一个很大的难题.面对 不了解的行业,新人往往是茫目的选择,或者是单面的选择, ...
- switch手柄可以连电脑吗_电脑可以拍照吗
电脑可以拍照吗?如果可以该怎么设置,相信对于很多想通过电脑进行拍照的朋友来说,这个问题相当重要,下面就给大家科普一下吧. 电脑可以拍照吗? 电脑可以拍照.电脑拍照的方法很多,随着如今摄像头的像素的提升 ...
- android 按钮事件添加事件吗,android为按钮添加事件的三种方法
Android中为按钮添加事件一般有三种方法,这里总结一下,当然其实这完全是java基础内容. 1.内部类: ? 代码片段,双击复制 btn.setOnClickListener(new OnClic ...
- 云影数码工作室-创业计划书
云 影 数 码 工 作 室 创业计划书 团队名称: 云飞工作室 负 责 人: 张建波 成员名单: 黄隆徽 李扬 黄健 刘磊 网 址: WWW.YUNFLY.COM 联系电话 ...
- 中职计算机老师的一天,信息技术教师的一天
信息技术教师在学校中的地位似乎是可有可无,特别是在评优评先过程中更是这样.但在实际工作中,信息技术教师常常忙得晕头转向,然而,在有些人眼里,信息技术老师就是应该这样,信息技术教师就应该是个修理工,是打 ...
- 2014年湛江新教育交流会总结
转载自sina博主"爱和榜样"的博文"2014年湛江新教育交流会总结",转载请直接引用原链接. 2014年湛江新教育交流会总结 为期半天的2014年湛江新教育交 ...
- 基于WinCE6.O操作系统的在线流媒体播放软件设计
http://www.hqew.com/tech/sheji/526049.html 摘要:互联网的迅猛发展和普及为流媒体业务发展提供了强大的市场动力,流媒体业务正变得日益流行.基于此设计了一个基于W ...
- 计算机信息技术专业毕业鉴定,信息技术毕业鉴定自我鉴定.doc
第一篇.信息技术专业人员工作情况自我鉴定 信息技术毕业鉴定自我鉴定 信息技术专业人员工作情况自我鉴定 这一学期,各位老师们立足岗位,团结协作,求真求实,教书育人,顺利而圆满地完成了各项教育教学任务,并 ...
最新文章
- 倒排索引的一些算法调研
- java操作大文件复制
- SPOJ SUMPRO(数学)
- CSS——规避脱标流和vertical-align
- ArrayList类contains方法实现原理
- azure云数据库_从Azure Databricks将数据加载到Azure SQL数据库
- 华为智慧屏云会议怎么操作_会议室预定系统有哪些?怎么操作
- 中国银行外币汇率查询
- Python制作局域网双人聊天软件(一)
- Spring框架学习总结(上)
- 记录一次C#爬虫记录,获取必应图片
- win7系统同步服务器,win7自动同步服务器
- 1021.Deepest Root
- 今日新闻快讯摘要十条
- XBOX GAMEPASS取消自动续费
- 篆刻小站之设计与开发
- Netty使用FileUpload报错Not represented by a file
- 行人重识别基础(一)
- 吉林华微电子: 自主研发砥砺行 助力打造“中国芯”
- 【转】前端——实用UI组件库