FileProvider 的使用(Failed to find configured root that contains/storage/emulated/0/DCIM/ )

FileProvider 的使用(Failed to find configured root that contains/storage/emulated/0/DCIM/ )首先扯点别的:今天不上班,在家里和剑宗喝了点酒,和同学聊了会天,也是挺开心,现在学会习。以前调用系统相机拍照的时候,流程是这样的privatevoidtakePhoto(){IntenttakePictureIntent=newIntent(MediaStore.ACTION_IMAGE_CAPTURE);if(takePictureIntent

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

Add on 2020-9-24: 可以参考源码 CameraDemo 的file_provider分支上的代码。

以前调用系统相机拍照的时候,流程是这样的

 private void takePhoto() { 
   
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) { 
   
	        //创建一个路径保存图片
            photoFile = ImageUtil.createImageFile();
            if (photoFile != null) { 
   
                photoURI = Uri.fromFile(photoFile);
                //传递一个Uri
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(takePictureIntent, TAKE_PHOTO);
            }
        }
    }

Jetbrains全家桶1年46,售后保障稳定

然后在onActivityResult方法中处理拍照结果。

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
   
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) { 
   
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) { 
   
	                //处理拍照的结果
                    processTakePhoto(photoFile.getPath());
                }
                break;
            default:
                break;
        }
    }

但是发现在7.0的系统上直接崩溃了,错误如下。
这里写图片描述

android.os.FileUriExposedException: 
file:///storage/emulated/0/Android/data/com.hm.camerademo/files/Picture
s/20170225_140305187933259.jpg exposed beyond app through 
ClipData.Item.getUri()

然后网上搜了一把,是 photoURI = Uri.fromFile(photoFile); 这种创建Uri的方式有问题了,不够安全。需要使用FileProvider来创建Uri.

使用FileProvider四部曲

第一步,指定一个FileProvider。在AndroidManifest.xml中声明一个条目

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp">
    <application ...>
        <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.myapp.fileprovider" android:grantUriPermissions="true" android:exported="false">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" />
        </provider>
        ...
    </application>
</manifest>

com.example.myapp是你的包名

第二步,指定想分享的目录。在res目录下新建一个xml目录,在xml目录下面新建一个xml文件。我新建的文件名叫filepaths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/DCIM/camerademo目录-->
    <!--/storage/emulated/0/DCIM/camerademo-->
    <external-path name="hm_DCIM" path="DCIM/camerademo" />

    <!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/Pictures/camerademo目录-->
    <!--/storage/emulated/0/Pictures/camerademo-->
    <external-path name="hm_Pictures" path="Pictures/camerademo" />

    <!--代表app 私有的存储区域 Context.getFilesDir()目录下的images目录-->
    <!--/data/user/0/com.hm.camerademo/files/images-->
    <files-path name="hm_private_files" path="images" />

    <!-- 代表app 私有的存储区域 Context.getCacheDir()目录下的images目录 -->
    <!--/data/user/0/com.hm.camerademo/cache/images-->
    <cache-path name="hm_private_cache" path="images" />

    <!--代表app外部存储区域根目录下的文件 Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)目录下的Pictures目录-->
    <!--/storage/emulated/0/Android/data/com.hm.camerademo/files/Pictures-->
    <external-files-path name="hm_external_files" path="Pictures" />

    <!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的images目录-->
    <!--/storage/emulated/0/Android/data/com.hm.camerademo/cache/images-->
    <external-cache-path name="hm_external_cache" path="images" />

</paths>

name=“name” URI 路径段,取值会隐藏你分享的目录的名字。比如下面这个

  <!--/storage/emulated/0/Android/data/com.hm.camerademo/cache/images-->
  <external-cache-path name="hm_file" path="images" />

会用hm_file 替代/storage/emulated/0/Android/data/com.hm.camerademo/cache/images

path=“path” 你分享的目录的名字

注意

java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/DCIM/camerademo/20170226_110056248725175.jpg错误产生原因。

  <external-path name="hm_DCIM" path="DCIM/camerademo" />
  <external-path name="hm_Pictures" path="Pictures/camerademo" />

我可以在 external-path目录下指定多个我想分享的目录,两个分享的目录的name取值不应该相同。我把上面两个的name字段都叫 hm_file,然后看看有什么问题。结果就是会报标题上的那个错误,实验一把

 <external-path name="hm_file" path="DCIM/camerademo" />
 <external-path name="hm_file" path="Pictures/camerademo" />

然后我生成一个Content URI。

  File imageFile = null;
  String storagePath;
  File storageDir;
  String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
  try { 
   
	 //文件路径是公共的DCIM目录下的/camerademo目录
     storagePath = Environment.getExternalStorageDirectory().getAbsolutePath()+ 
     File.separator + "DCIM" + File.separator + "camerademo";

     storageDir = new File(storagePath);
     storageDir.mkdirs();
     imageFile = File.createTempFile(timeStamp, ".jpg", storageDir);
     Log.e(TAG, imageFile.getAbsolutePath());
     } catch (IOException e) { 
   
          e.printStackTrace();
     }
return imageFile;
//文件路径
/storage/emulated/0/DCIM/camerademo/20170226_110056248725175.jpg
//生成Uri
photoFile = ImageUtil.createImageFile();
photoURI = FileProvider.getUriForFile(this, "com.hm.camerademo.fileprovider", photoFile);

但是报错了。错误如下

 java.lang.IllegalArgumentException: Failed to find configured root 
 that contains 
 /storage/emulated/0/DCIM/camerademo/20170226_110056248725175.jpg
                                                                     

我把上面生成文件的路径改一下

//路径是公共存储路径Pictures目录下的camerademo目录
 storagePath = Environment.getExternalStorageDirectory().getAbsolutePath()+ 
     File.separator + "Pictures" + File.separator + "camerademo";
 
//生成的文件路径
/storage/emulated/0/Pictures/camerademo/20170226_1104551680202685.jpg
//可以正常生成Uri的路径
/hm_file/20170226_1104551680202685.jpg

上面的问题说明 在filePath.xml 文件中,如果要在同一个存储路径下,指定两个共享的目录,如下所示,那么两个共享路径的name字段取值不应该相同,如果两者相同,那么后面的一行指定的path(/storage/emulated/0/Pictures/camerademo)会覆盖上面一行指定的path(/storage/emulated/0/DCIM/camerademo)

//	共享目录的根目录都是 /storage/emulated/0/
 <external-path name="hm_file" path="DCIM/camerademo" />
 <external-path name="hm_file" path="Pictures/camerademo" />

第三步 为一个文件生成 Content URI

   File imageFile = null;
   String storagePath;
   File storageDir;
   String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        try { 
   
            storagePath = App.getInstance().getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath();
            storageDir = new File(storagePath);
            storageDir.mkdirs();
            imageFile = File.createTempFile(timeStamp, ".jpg", storageDir);
        } catch (IOException e) { 
   
            e.printStackTrace();
        }
//创建Uri
Uri  photoURI = FileProvider.getUriForFile(this, "com.hm.camerademo.fileprovider", imageFile );
com.hm.camerademo.fileprovider

要和在AndroidManifest.xml中指定的一样。不然会报错。

第四步 分享一个 Content URI
这个例子中我们是向系统的相机传递一个Uri

photoURI = FileProvider.getUriForFile(this, "com.hm.camerademo.fileprovider", photoFile);
Log.e(TAG, photoURI.getPath());
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, TAKE_PHOTO);

最后附上两张图,图片来自参考文档2

图一:使用Uri.fromFile()的方式生成一个Uri
这里写图片描述

图一:使用FileProvider.getUriForFile(this, “com.hm.camerademo.fileprovider”, photoFile);的方式生成一个Uri

这里写图片描述

参考链接:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222862.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JWT原理介绍

    JWT原理介绍首先,OAuth2和jwt无必然的联系。OAuth2用在使用第三方账号登录的情况(比如使用weibo,qq,github登录某个app)JWT是用在前后端分离,需要简单的对后台API进行保护时使用.(前后端分离无session,频繁传用户密码不安全)OAuth2是一个相对复杂的协议,有4种授权模式,其中的accesscode模式在实现时可以使用jwt才生成code,也可以不用…

    2022年10月18日
    0
  • 颜色代码对应表「建议收藏」

    颜色代码对应表「建议收藏」颜色代码表http://www.knowsky.com/tools/advancedColorPicker.swfwidth=900height=500先用鼠标左键在左边大的方框内移动获取颜色(黑色

    2022年8月1日
    1
  • 十大it博客_中国it名人

    十大it博客_中国it名人IT名人博客推荐(15个)1.李彦宏百度公司总裁博客地址:http://hi.baidu.com/liyanhong2.张朝阳搜狐董事局主席兼CEO博客地址:http://charles.blog.sohu.com/3.马云阿里巴巴集团主席兼首席执行官博客地址:http://yunma.blog.china.alibaba.com/4.雷军曾任金山…

    2022年8月30日
    0
  • 小龙女李若彤_网红为什么能成为网红

    小龙女李若彤_网红为什么能成为网红小龙女彤彤为何能红如何让营销推到网民心里去呢?最关键的就是你如何去读懂网民的心理,摸清楚哪里才是最需要推广的所在。以网络游戏为例,我们来看看如何正确选好角度进行营销推广。通过一个案例,我们来看一个成功的网络推广,从策划到实施要如何运作。 在2006年末,笔者开始尝试将

    2022年10月19日
    1
  • Java中的数据类型详解——boolean类型

    Java中的数据类型详解——boolean类型BooleanTest01.java/* 1、在java语言中boolean类型只有两个值,没有其他值: true和false。 不像c或者c++,c语言中1和0也可以表示布尔类型。 2、boolean类型在实际开发中使用在哪里呢? 使用在逻辑判断当中,通常放在条件的位置上(充当条件)。*/publicclassBooleanTest01{ publicstaticvoidmain(String[]args){ //错误:不兼容的类型:int无法转换为boole

    2022年7月8日
    62
  • could not get lock /var/lib/apt/lists/lock_var目录满了有什么影响

    could not get lock /var/lib/apt/lists/lock_var目录满了有什么影响在Ubuntu中,有时候运用sudo apt-getinstall安装软件时,会出现一下的情况E:Couldnotgetlock/var/lib/dpkg/lock-open(11:Resourcetemporarilyunavailable)E:Unabletolocktheadministrationdirectory(/var/lib/dpk

    2022年10月6日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号