图片来自 Android 6 中的图库(棉花糖)
Posted
技术标签:
【中文标题】图片来自 Android 6 中的图库(棉花糖)【英文标题】:Image from Gallery in Android 6(Marshmallow) 【发布时间】:2016-02-10 14:52:18 【问题描述】:在我的应用程序中,我试图从厨房中挑选图像,以便将该图像传递给服务器。
代码在 android 5 及更低版本上运行良好,但对于 Nexus 5 上的 Android 6,我无法获取图像信息。 我得到的日志跟踪
注意:代码在 Android 5 及以下版本上运行良好
11-06 12:27:43.736: W/System.err(31678): java.lang.SecurityException: Permission Denial: reading com.google.android.apps.photos.contentprovider.MediaContentProvider uri content://com.google.android.apps.photos.contentprovider/0/1/content%3A//media/external/images/media/19138/ACTUAL/94710853 from pid=31678, uid=10111 requires the provider be exported, or grantUriPermission()
11-06 12:27:43.757: W/System.err(31678):
at android.os.Parcel.readException(Parcel.java:1599)
11-06 12:27:43.757: W/System.err(31678):
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
11-06 12:27:43.757: W/System.err(31678):
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
11-06 12:27:43.757: W/System.err(31678):
at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
11-06 12:27:43.757: W/System.err(31678):
at android.content.ContentResolver.query(ContentResolver.java:491)
11-06 12:27:43.757: W/System.err(31678):
at android.content.ContentResolver.query(ContentResolver.java:434)
11-06 12:27:43.758: W/System.err(31678):
at org.apache.cordova.file.ContentFilesystem.openCursorForURL(ContentFilesystem.java:258)
11-06 12:27:43.758: W/System.err(31678):
at org.apache.cordova.file.ContentFilesystem.getFileMetadataForLocalURL(ContentFilesystem.java:169)
11-06 12:27:43.758: W/System.err(31678):
at org.apache.cordova.file.FileUtils.getFileMetadata(FileUtils.java:822)
11-06 12:27:43.758: W/System.err(31678):
at org.apache.cordova.file.FileUtils.access$500(FileUtils.java:52)
11-06 12:27:43.758: W/System.err(31678):
at org.apache.cordova.file.FileUtils$15.run(FileUtils.java:394)
11-06 12:27:43.758: W/System.err(31678):
at org.apache.cordova.file.FileUtils$25.run(FileUtils.java:551)
11-06 12:27:43.758: W/System.err(31678):
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
11-06 12:27:43.758: W/System.err(31678):
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
11-06 12:27:43.758: W/System.err(31678):
at java.lang.Thread.run(Thread.java:818)
【问题讨论】:
很好的解释inthecheesefactory.com/blog/… 我猜你应该尝试在相同的上下文中解码图像,而不将 uri 传递到另一个上下文并在那里解码图像(如 startActivity)。 【参考方案1】:这样做... on Button 点击检查 SDK 版本
if (Build.VERSION.SDK_INT >= 23)
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE))
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
else
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(MainActivity.this,
new String[]Manifest.permission.READ_EXTERNAL_STORAGE,
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
else
ActivityCompat.requestPermissions(MainActivity.this,
new String[]Manifest.permission.READ_EXTERNAL_STORAGE,
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
else
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, SELECT_PHOTO);
然后在 Override 方法 onRequestPermissionsResult 中写下这段代码:
case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
// permission was granted, yay! Do the
// contacts-related task you need to do.
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, SELECT_PHOTO);
else
// permission denied, boo! Disable the
// functionality that depends on this permission.
return;
之后
@Override
protected void onActivityResult(int reqCode, int resultCode, Intent data)
super.onActivityResult(reqCode, resultCode, data);
switch (reqCode)
case SELECT_PHOTO:
if (resultCode == RESULT_OK)
try
final Uri imageUri = data.getData();
final InputStream imageStream = getContentResolver().openInputStream(imageUri);
final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
contactimage.setImageBitmap(selectedImage);
catch (FileNotFoundException e)
e.printStackTrace();
【讨论】:
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE 是什么,我在哪里初始化它?? 它是一个静态 int 值,为它分配任何 int 值,但该值不应用于任何其他请求。例如,如果相机使用值 1,那么您可以使用除 1 之外的任何整数值..【参考方案2】:我相信您需要在运行时向用户请求权限(这是从 api 22 到 23 最明显的变化之一)。
你可以试试这个sn-p,提取自Android Developers permission page
if (Build.VERSION.SDK_INT >= 23)
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_EXTERNAL_STORAGE))
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
else
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]Manifest.permission.READ_EXTERNAL_STORAGE,
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
如果有帮助,请告诉我。
【讨论】:
【参考方案3】:为了从 Marshmallow 中的图库中获取图像,您需要在运行时授予 READ_EXTERNAL_STORAGE 权限。 Android 版本 M 改变了授予应用程序权限的方式。
在 Marshmallow 之前,所有必需的权限都是在安装时一次性授予的。但在 Marshmallow 中,只有在需要该权限时才会向用户请求权限,并且用户必须允许或拒绝该权限。
以下两个链接将为您提供更多帮助。链接 1 来自 Android 的官方文档,链接 2 是一个博客,它通过一个工作示例解释了这个问题。
链接1:http://developer.android.com/training/permissions/requesting.html
链接2:http://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
【讨论】:
【参考方案4】:我遇到了同样的问题。使用
从图库中选择图像后,图像显示在 Imageview 中Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, videoIdentifier);
并从 URI 解码位图图像
但保存 URI 以供将来使用并重新打开应用程序并重新使用保存的 URI 不起作用。无法从 URI 解码位图。
我通过从 URI 路径中提取原始内容 uri 解决了这个问题
public String RemoveUnwantedString(String pathUri)
//pathUri = "content://com.google.android.apps.photos.contentprovider/-1/2/content://media/external/video/media/5213/ORIGINAL/NONE/2106970034"
String[] d1 = pathUri.split("content://");
for (String item1:d1)
if (item1.contains("media/"))
String[] d2 = item1.split("/ORIGINAL/");
for (String item2:d2)
if (item2.contains("media/"))
pathUri = "content://" + item2;
break;
break;
//pathUri = "content://media/external/video/media/5213"
return pathUri;
【讨论】:
【参考方案5】:试试这个
这是我用其他示例创建的简单方法
在需要的地方调用 CHECKGALLERYPERMISSION() 方法并将代码粘贴到方法中
private void CHECKGALLERYPERMISSION()
int MY_READ_PERMISSION_REQUEST_CODE =1 ;
int PICK_IMAGE_REQUEST = 2;
if (ContextCompat.checkSelfPermission(YourActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED)
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);
else
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
requestPermissions(
new String[]android.Manifest.permission.READ_EXTERNAL_STORAGE,
MY_READ_PERMISSION_REQUEST_CODE);
else
@Override
public void onRequestPermissionsResult(int requestCode, String[]
permissions, int[] grantResults)
if (requestCode == MY_READ_PERMISSION_REQUEST_CODE
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null)
Uri uri = data.getData();
try
Bitmap bitmap = MediaStore.Images.Media.getBitmap(YourActivity.this.getContentResolver(), uri);
imageview.setImageBitmap(bitmap);
catch (IOException e)
e.printStackTrace();
注意
-
在片段中使用 getactivity() 而不是 activity.this
如果 android.Manifest.permission.READ_EXTERNAL_STORAGE 不起作用,请在所有地方将其更改为 Manifest.permission.READ_EXTERNAL_STORAGE
【讨论】:
以上是关于图片来自 Android 6 中的图库(棉花糖)的主要内容,如果未能解决你的问题,请参考以下文章