问题出现
尝试将拍摄的图像存储至手机自定义的存储空间,不料却一直报错,主要问题是在使用 FileProvider 从文件路径中获取 Uri 时出现异常。
相关代码
报错区域的文件路径相关的代码
主要是在 File imageDir = new File(getExternalCacheDir(), "Gallery");过程中,getExternalCacheDir()报了此异常。
java
File imageDir = new File(getExternalCacheDir(), "Gallery");
if (!imageDir.exists()) {
imageDir.mkdir();
}
mPhotoFile = new File(imageDir,"output_image.jpg");
if(mPhotoFile.exists()){
mPhotoFile.delete();
}
try {
mPhotoFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mImageUri = FileProvider.getUriForFile(CameraActivity.this, getPackageName() + ".fileprovider", mPhotoFile);
} else {
mImageUri = Uri.fromFile(mPhotoFile);
}
在AndroidManifest.xml配置FileProvider
其中 ${applicationId} 为 项目的包名,com.example.app , 具体值可以在项目模块文件夹中的 build.gradle 中找到
@xml/file_paths:为项目路径下 res/xml/file_paths.xml,file_paths为文件名
bash
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
file_paths.xml内容如下:
其中每个子标签中的 name 指的子文件夹名字,path 指路径
xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="external" path="path" />
<!--代表app外部缓存区域的根目录,与Context.getExternalCacheDir()获取的路径对应。-->
<external-cache-path name="Gallery" path="Android/data/com.example.app/files" />
</paths>
问题原因分析
结合上述java代码中FileProvider.getUriForFile的具体实现,发现其对应的文件夹路径为:getExternalCacheDir()/path/name,所以下面情况会形成:getExternalCacheDir()/Android/data/com.example.app/files/Gallery 这个路径,明显与File imageDir = new File(getExternalCacheDir(), "Gallery"); 不符合,所以会报异常
问题解决
其实最本质的出错是在 file_paths.xml 的配置上,把其中的 external-cache-path 改为下面的情况,问题即解决。即path = '.' 表示当前路径(该路径即为Context.getExternalCacheDir()获取的路径)下,建立BEGallery子文件夹,path不用进行重新指定其他路径。
xml
<external-cache-path name="Gallery" path="." />
如果您就想在 path中指定路径,则需要更改代码中的 imageDir.mkdir(); ,将这个创建单个文件夹,改为 imageDir.mkdirs(); 即创建多层文件夹,也可以解决此问题。