Android 10

在Android 10 文件储存机制修改为沙盒模式,

App 只能访问自己目录下的文件和公共媒体文件,
所以,即使获取了存储的权限,访问外部的存储受到了限制,也就是说除了自己目录和公共媒体文件,
读取其它的文件就会报:open failed: EACCES (Permission denied)。

解决方法:

第一种方法:在 AndroidManifest.xml 的 application 添加属性:
android:requestLegacyExternalStorage=“true”
这代码意思是使用旧存储方式,但不建议使用此法,因为在Android 10以后该配置就会失效!
(写了该配置启动app又删除该配置又启动app,就不会报错,因为已经记录了用该配置存储,当卸载再重新安装,又会报错)

第二种:既然无法读取file(可以获得file实例,不能读取(使用)),那就通过该file的uri创建
新的一样内容的file在自己的目录下,再读取新的file即可
以下是根据uri创建新的file的代码:

    //====根据 uri(content或file开头都行)生成新的file
    public File getFile(Uri uri) {
        //https://www.jb51.net/article/181745.htm

        //文件夹  这两种文件夹都会随软件卸载而删掉
        File folder = this.getExternalCacheDir();//在Android>data>包名>的cache目录下,一般存放临时缓存数据
        //File folder = this.getExternalFilesDir("image");//在Android>data>包名>的files的image目录下,一般放一些长时间保存的数据

        if (!folder.exists()){
            folder.mkdir();
        }
        //file图片
        File file=new File(folder.getAbsolutePath()+File.separator+"newFile.jpg");

        try {
            //根据uri获取输入字节流
            InputStream inputStream = getContentResolver().openInputStream(uri);

            //==把输入流写进file里
            FileOutputStream fileOutputStream=new FileOutputStream(file);
            byte[] buffer=new byte[1024];
            int byteRead;
            while (-1 != (byteRead=inputStream.read(buffer))){
                fileOutputStream.write(buffer,0,byteRead);
            }
            fileOutputStream.flush();
            inputStream.close();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }

可能有时候只有file对象,没有uri,可通过以下方法获取 其uri:

因Android 7.0 行为变更,通过FileProvider在应用间共享文件,所以要准备以下工作:

1:在res层新建xml的层(若有则不需):右键res-》Folder-》-》XML Resources Folder-》Finnish, 然后在xml层新建file_paths.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <!--path:代表该目录里的所有文件-->
        <root-path
            name="root"
            path="." />
        <cache-path
            name="image_cache"
            path="." />
    </paths>
</resources>

2:在配置清单文件AndroidManifest.xml 的 application 里添加如下代码:

        <!--provider的参数:
        name:指向提供者所适应的类
        authorities:项目包名.xxx;  xxx只能小写否则运行时抛出异常
        exported:这个提供者是否开放给外部app
        grantUriPermissions:是否允许获取参数resource这个文件的权限

        meta-data里的参数resource:配置需要访问哪些目录,也就是刚才的file_paths文件-->
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.gx.picture.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

准备完后,就可以用以下代码用 FileProvider 来获取 conten://URI 类型的uri了:

	//参数1 为content,参数2 为AndroidManifest.xml的provider里的authorities值,参数3 为 file 实例(该文件的file实例)
	Uri uri=FileProvider.getUriForFile(MainActivity.this,"com.gx.picture.fileprovider",file);
    /**
    ps:奇怪的是Android 7 以下的,若 uri用  Uri imageUri=Uri.fromFile(cameraFile) 来获取,
    在拍照后 无法获取拍照后的照片,即不执行onActivityResult方法,也不报错,
    所以, 不管哪个版本的Android 都用 FileProvider 来获取 uri!!
    */
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值