从图库中选择图像会出现错误 Android N
Posted
技术标签:
【中文标题】从图库中选择图像会出现错误 Android N【英文标题】:Picking an image from gallery gives error Android N 【发布时间】:2019-04-17 08:55:12 【问题描述】:我在从 android N 的意图中检索 Uri 时遇到问题。
据我所知,在 Android 24 及更高版本上要获得外部 Uri,您需要在 Manifest
中声明 FileProvider
。一切都完成了,它可以与相机一起使用,但是当我尝试从图库中获取图像时,onActivityResult data.getData();
出现错误@
这些是我的一些代码示例:
public void getPictureFromGallery()
picUriCar = null;
try
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, PIC_SELECT);
catch (ActivityNotFoundException e)
Toast.makeText(MainActivity.this, getResources().getString(R.string.text_error_no_gallery_app),
Toast.LENGTH_SHORT).show();
还有onActivityResult
:
else if(requestCode == PIC_SELECT)
picUriCar = data.getData();
if (picUriCar != null)
performCrop();
据我所知data.getData()
返回一个 Uri,这在 Marshmallow 上运行正常,但在 Nougat 手机上我收到此错误:
java.lang.RuntimeException: 传递结果失败 ResultInfowho=null, request=5, result=-1, data=Intent dat=content://com.android.externalstorage.documents/document/4996-1EFF:DCIM/100ANDRO/DSC_0004.JPG flg=0x1 到活动 com.company.example/com.company.example.MainActivity: java.lang.SecurityException: Uid 10246 没有 uri 的权限 0@ 内容://com.android.externalstorage.documents/document/4996-1EFF%3ADCIM%2F100ANDRO%2FDSC_0004.JPG 在 android.app.ActivityThread.deliverResults(ActivityThread.java:4267) 在 android.app.ActivityThread.handleSendResult(ActivityThread.java:4310) 在 android.app.ActivityThread.-wrap20(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1628) 在 android.os.Handler.dispatchMessage(Handler.java:110) 在 android.os.Looper.loop(Looper.java:203) 在 android.app.ActivityThread.main(ActivityThread.java:6361) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924) 引起:java.lang.SecurityException: Uid 10246 没有权限访问uri 0 @ 内容://com.android.externalstorage.documents/document/4996-1EFF%3ADCIM%2F100ANDRO%2FDSC_0004.JPG 在 android.os.Parcel.readException(Parcel.java:1683) 在 android.os.Parcel.readException(Parcel.java:1636) 在 android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:3213) 在 android.app.Instrumentation.execStartActivity(Instrumentation.java:1525) 在 android.app.Activity.startActivityForResult(Activity.java:4235) 在 android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767) 在 android.app.Activity.startActivityForResult(Activity.java:4194) 在 android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754) 在 com.company.example.MainActivity.performCrop(MainActivity.java:1654) 在 com.company.example.MainActivity.onActivityResult(MainActivity.java:1534) 在 android.app.Activity.dispatchActivityResult(Activity.java:6928) 在 android.app.ActivityThread.deliverResults(ActivityThread.java:4263) 在 android.app.ActivityThread.handleSendResult(ActivityThread.java:4310) 在 android.app.ActivityThread.-wrap20(ActivityThread.java) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1628) 在 android.os.Handler.dispatchMessage(Handler.java:110) 在 android.os.Looper.loop(Looper.java:203) 在 android.app.ActivityThread.main(ActivityThread.java:6361) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
我的问题是:
如何将data.getData()
uri 传递给 picUriCar 而不会出现任何错误?
【问题讨论】:
【参考方案1】:使用此代码创建选择图像的新意图:
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType(image/*);
startActivityForResult(Intent.createChooser(intent, ""), Constants.SELECT_PICTURE);
在onActivityResult
中使用此代码:
if (resultCode == Activity.RESULT_OK)
if (requestCode == Constants.SELECT_PICTURE)
Uri selectedImageUri = data.getData();
try
if (isNewGooglePhotosUri(selectedImageUri))
resultFile = getPhotoFile(selectedImageUri);
else
resultFile = getFilePathForGallery(selectedImageUri);
if (resultFile == null)
//error
return;
catch (Exception e)
e.printStackTrace();
//error
return;
这里还有一些我在代码中使用的有用函数:
private File getFilePathForGallery(Uri contentUri)
String path = null;
String[] proj = MediaStore.Images.Media.DATA;
Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
if (cursor.moveToFirst())
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
path = cursor.getString(column_index);
cursor.close();
return new File(path);
public static boolean isNewGooglePhotosUri(Uri uri)
return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
private File getPhotoFile(Uri selectedImageUri)
try
InputStream is = mActivityInstance.getContentResolver().openInputStream(selectedImageUri);
if (is != null)
Bitmap pictureBitmap = BitmapFactory.decodeStream(is);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bytes);
File output = new File(FileManager.getImageCacheDir(mActivityInstance), System.currentTimeMillis() + ".jpg");
output.createNewFile();
FileOutputStream fo = new FileOutputStream(output);
fo.write(bytes.toByteArray());
fo.close();
return output;
catch (Exception e)
e.printStackTrace();
return null;
FileManager 类的函数:
private static File getCacheDir(Context context)
File cacheDir = context.getExternalFilesDir(null);
if (cacheDir != null)
if (!cacheDir.exists())
cacheDir.mkdirs();
else
cacheDir = context.getCacheDir();
return cacheDir;
public static File getImageCacheDir(Context context)
File imageCacheDir = new File(getCacheDir(context), "cache_folder");
if (!imageCacheDir.exists())
imageCacheDir.mkdirs();
return imageCacheDir;
您还需要在您的 xml 文件夹中创建新的 xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_files"
path="." />
</paths>
然后将新的provider
添加到清单文件中:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="$applicationId.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/your_xml_file" />
</provider>
【讨论】:
感谢您的回答。但我无法导入 FileManager。 FileManager 是来自特定库还是什么? @ТеодорМитев 我添加了 FileManager 类的函数来回答 好吧,我实现了代码,没有语法错误,但它似乎仍然不起作用。picUriCar = FileProvider.getUriForFile(this, authority, resultFile);
这会抛出一个异常,上面写着:Java.lang.IllegalArgumentException: Failed to find configured root that contains /mnt/media_rw/4996-1EFF/DCIM/100ANDRO/DSC_0004.JPG 2018-11-14 16:47:44.151 24744-24744/com.company.example W/example : type=1400 audit(0.0:8811): avc: denied getattr for path="/mnt/media_rw" dev="tmpfs" ino=8056 scontext=u:r:untrusted_app:s0:c5
@ТеодорМитев 检查清单中的提供商。是否正确实施。我也不在我的代码中使用 FileProvider.getUriForFile 吗?你从哪里得到的?
@ТеодорМитев 或提供堆栈跟踪和崩溃的代码【参考方案2】:
我做了一些检查,并且一如既往的解决方案比我预期的要简单。这是我的 performCrop 函数。单击视图时,我有两个选项。从图库中获取图像或使用相机捕获图像。我记得只有在我修复了相机问题后才会出现画廊选项问题。所以问题可能在裁剪代码中的某个地方。所以这就是我所做的:
public void performCrop(boolean cameraShot)
try
Intent cropIntent = new Intent("com.android.camera.action.CROP");
//indicate image type and Uri
//cropIntent.setDataAndType(picUri, "image");
cropIntent.setDataAndType(picUriCar, "image/*");
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 2);
cropIntent.putExtra("aspectY", 1);
//indicate output X and Y
cropIntent.putExtra("outputX", 1024);
cropIntent.putExtra("outputY", 512);
cropIntent.putExtra("scale", true);
cropIntent.putExtra("return-data", false);
Uri uri;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || !cameraShot)
uri = Uri.fromFile(croppedFileCar);
else
String authority = "com.company.example.provider";
uri = FileProvider.getUriForFile(
MainActivity.this,
authority,
croppedFileCar);
cropIntent.setClipData(ClipData.newRawUri( "", uri ) );
cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
请注意 - if (Build.VERSION.SDK_INT
所以基本上它背后的逻辑是,如果图片不是相机提供的(在onActivityResult中确定)或者API低于24,执行该行:
uri = Uri.fromFile(croppedFileCar);
否则使用 FileProvider。在我进行这些更改之前,应用程序在从图库中选择图像时崩溃了。我不知道为什么它现在有效,但如果有人知道答案,我会很高兴听到它。
【讨论】:
以上是关于从图库中选择图像会出现错误 Android N的主要内容,如果未能解决你的问题,请参考以下文章
Android:如何在设置图像视图时检测从图库中选择的图像方向(纵向或横向)?