java.lang.IllegalArgumentException:无法找到包含 /storage/emulated/0/Pictures/ 的配置根目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40498380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Pictures/
提问by J2112O
Looking for some help on an error I am getting while trying to store Pictures taken with the camera for an App I am trying to develop. The error is
在尝试存储使用相机拍摄的照片以用于我正在尝试开发的应用程序时遇到的错误寻求帮助。错误是
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Pictures/JPEG20161108_153704_
java.lang.IllegalArgumentException:无法找到包含 /storage/emulated/0/Pictures/JPEG20161108_153704_ 的配置根目录
The logcat points to this method in my code at the line where FileProvider.getUriForFile is being called..
logcat 在我的代码中在调用 FileProvider.getUriForFile 的行中指向此方法。
private void dispatchTakePhoto() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivity(takePictureIntent); // this worked originally
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, ""+e);
}
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(TallyActivity2.this,
"com.example.bigdaddy.pipelinepipetally.fileprovider", photoFile);
takePictureIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
This method is used to create the image file
此方法用于创建图像文件
private File createImageFile() throws IOException {
/* Create an image file name */
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String imageFileName = "JPEG" + timeStamp + "_";
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsoluteFile(), imageFileName);
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
/* Tried this also, not working. Leaving for debugging.
File image = File.createTempFile(
imageFileName,
".jpg",
storageDir
);*/
File image = new File(path, imageFileName);
try {
/* Making sure the Pictures directory exist.*/
path.mkdir();
storageDir.createNewFile();
}catch (Exception e) {
e.printStackTrace();
}
/* Save a file: path for use with ACTION_VIEW intents */
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
Here is the onActivityResult()
method, where I am wanting to save the image captured to a class with the saveImage() method and also setting the thumbnail to an ImageView
. The saveImage() method returns a byte so I can pass the byte in a Bundle through an Intent to another full screen activity, where it will be displayed, should the user click on the thumbnail ImageView
.
这是onActivityResult()
方法,我想使用 saveImage() 方法将捕获的图像保存到一个类中,并将缩略图设置为ImageView
. saveImage() 方法返回一个字节,因此我可以通过 Intent 将 Bundle 中的字节传递给另一个全屏活动,如果用户单击缩略图,它将在此处显示ImageView
。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
/* If it's equal to my REQUEST_IMAGE_CAPTURE var, we are all good. */
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
/*Saving to the Pipe class with the saveImage() method below.*/
sDummyImagePicByte = saveImage(imageBitmap);
/* Going ahead an setting the thumbnail here for the picture taken*/
mPipePicImage.setImageBitmap(imageBitmap);
Log.i(TAG,Arrays.toString(sDummyImagePicByte)+" after assignment from saveImage()");
}
}
Here is the Manifest.xml
file
这是Manifest.xml
文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.bigdaddy.pipelinepipetally">
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<application
android:allowBackup="true"
android:debuggable="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="HardcodedDebugMode">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".TallyActivity2"
android:windowSoftInputMode="adjustResize">
</activity>
<activity
android:name=".JobAndDbActivity"
android:windowSoftInputMode="adjustResize">
</activity>
<activity
android:name=".ExistingTallyActivity"
android:windowSoftInputMode="adjustResize">
</activity>
<activity android:name=".ImageToFullscreen"
android:windowSoftInputMode="adjustResize">
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.bigdaddy.pipelinepipetally.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
</application>
</manifest>
Here is the file_paths.xml
file that I created and put in the app/res/xml/ folder (which I created also). Not sure if this is the correct location (for the folder).
这是file_paths.xml
我创建并放入 app/res/xml/ 文件夹(也是我创建的)中的文件。不确定这是否是正确的位置(对于文件夹)。
<paths >
<files-path name="my_images" path="files/"/>
...
</paths>
Also this is the onRequestPermissionsResult()
这也是 onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CAMERA:
/* if request is canceled, the result arrays are empty */
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
/* Permissions granted so the mPermissionIsGranted boolean is set to true*/
mPermissionIsGranted = true;
} else {
/*
Permissions denied so the mPermissionIsGranted boolean stays false here and
providing a Toast message to the user, letting them know that camera permissions
are required for this feature.
*/
Toast.makeText(getApplicationContext(),"Camera permissions required\nfor this" +
"feature.",
Toast.LENGTH_LONG).show();
/* Continuing to hold the false setting to this boolean since not granted.*/
mPermissionIsGranted = false;
}
break;
/* For accessing and writing to the SD card*/
case MY_PERMISSIONS_REQUEST_SD_CARD:
/* if request is canceled, the result arrays are empty */
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
/* Permissions granted so the mPermissionIsGranted boolean is set to true*/
mPermissionIsGranted = true;
} else {
/*
Permissions denied so the mPermissionIsGranted boolean stays false here and
providing a Toast message to the user, letting them know that camera permissions
are required for this feature.
*/
Toast.makeText(getApplicationContext(),"SD Card permissions required\nfor this"+
"feature.",
Toast.LENGTH_LONG).show();
/* Continuing to hold the false setting to this boolean since not granted.*/
mPermissionIsGranted = false;
}
break;
/* For the GPS location permissions.*/
default: MY_PERMISSIONS_REQUEST_FINE_LOCATION:
/* Still to be implemented .*/
break;
}
}
I sure appreciate any help on this. I am still new and learning Android. Thanks in advance.
我当然感谢您对此的任何帮助。我还是新手,正在学习 Android。提前致谢。
回答by Sagar Chavada
Its little late.. but i finally able to solved.
它有点晚了..但我终于能够解决。
As per the documentation: The path component only corresponds to the path that is returned by getExternalFilesDir() when called with Environment.DIRECTORY_PICTURES.
根据文档: The path component only corresponds to the path that is returned by getExternalFilesDir() when called with Environment.DIRECTORY_PICTURES.
so use
所以用
getExternalFilesDir(Environment.DIRECTORY_PICTURES)
getExternalFilesDir(Environment.DIRECTORY_PICTURES)
instead of
代替
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
and your path should be like this:
你的路径应该是这样的:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="InstructiveRide" path="Android/data/com.package.ride/files/Pictures"/>
</paths>
and write this if you have a subdirectory under Picture directory.
如果您在图片目录下有子目录,请写下这个。
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="InstructiveRide" path="Android/data/com.package.ride/files/Pictures/InstructiveRide/"/>
</paths>
回答by Salman Nazir
I use to have boilerplate code for all of the paths for File provider. You will never get such type of errors.
我曾经为文件提供程序的所有路径提供样板代码。您永远不会遇到此类错误。
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external" path="." />
<external-files-path name="external_files" path="." />
<cache-path name="cache" path="." />
<external-cache-path name="external_cache" path="." />
<files-path name="files" path="." />
</paths>
For more details, You can check FileProvider - Specifying available Files
有关更多详细信息,您可以查看FileProvider - 指定可用文件
回答by CommonsWare
<files-path name="my_images" path="files/"/>
This points to a files/
directory inside of getFilesDir()
. However, that is not where createImageFile()
is looking to place the file. Instead, it is using Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
. You need to:
这指向files/
的目录中getFilesDir()
。但是,这不是createImageFile()
要放置文件的位置。相反,它使用Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
. 你需要:
Decide which location is the correct one (or choose another option than either of those), then
Synchronize the implementations
确定哪个位置是正确的(或选择其中一个之外的另一个选项),然后
同步实现
回答by user1154390
I am also trying to upgrade my application to avoid FileUriExposedException. I wanted to achieve the same that was mentioned in the actual question. I managed to work with
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
我也在尝试升级我的应用程序以避免 FileUriExposedException。我想实现与实际问题中提到的相同。我设法使用
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
Only trick is use following path
唯一的技巧是使用以下路径
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="." />
</paths>
I got this hint from following blog.
我从以下博客中得到了这个提示。
https://proandroiddev.com/sharing-files-though-intents-are-you-ready-for-nougat-70f7e9294a0b
https://proandroiddev.com/sharing-files-though-intents-are-you-ready-for-nougat-70f7e9294a0b
I spent few hours to figure out. I hope It would safe someone time.
我花了几个小时才弄清楚。我希望它会安全的人时间。
回答by saleh sereshki
My problem was that I defined a suffix for my application id in the build.gradle
file for debug
mode, and when I ran the application in the debug mode, the package name did not compatible with what I mentioned in the code. It is better to set the applicationId(packagename) variable in your xml
and java
code.
我的问题是我在build.gradle
文件 for debug
mode 中为我的应用程序 id 定义了一个后缀,当我在调试模式下运行应用程序时,包名与我在代码中提到的不兼容。这是更好地设置的applicationID(包名称)变量在你xml
和java
代码。
for doing this in your menifest for your provider set :
在您的供应商集的清单中执行此操作:
android:authorities="${applicationId}.fileprovider"
and in your java code :
并在您的 Java 代码中:
Uri photoURI = FileProvider.getUriForFile(context,
getApplicationContext().getPackageName()+".fileprovider",
and for your provider path create two different files for different build variants(release and debug)
并为您的提供程序路径为不同的构建变体(发布和调试)创建两个不同的文件
for release :
发布:
<external-path name="my_images" path="Android/data/com.android.example/files/Pictures" />
and for debug:
和调试:
<external-path name="my_images" path="Android/data/com.android.example.debug/files/Pictures" />