图片来自 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 中的图库(棉花糖)的主要内容,如果未能解决你的问题,请参考以下文章

安卓 6.0 棉花糖。无法写入 SD 卡

安卓6.0(棉花糖)新特性汇总

39.Android版本小知识

android棉花糖和棒棒糖中的推送通知问题

Android Studio getSlotFromBufferLocked:棉花糖中的未知缓冲区错误

三星FOTA来了,棉花糖还远吗?