图片uri不会在某些android设备上的ImageView上显示图像

问题描述:

我有一个ImageView。当你点击一个ImageView时,它会打开一个图库,然后你选取一个图像并在ImageView上显示它。我有一个条件,当我关闭我的应用程序,然后我打开它,图像将保留在那里。 因此,我将图像Uri存储在sharedprefrence上。 而在打开应用程序时,我正在检索相同的Uri并尝试在imageView上显示图像。图片uri不会在某些android设备上的ImageView上显示图像

但是,在一些手机 - 图像看起来像Mi(棒棒糖),三星(KitKat) 完美,但它并不出现在像摩托罗拉(棉花糖),One Plus One(棉花糖)的手机中。 任何想法为什么发生? 这里是我的代码

对于拾取图像我使用

Intent intent=new Intent();intent.setType("image/*"); 
intent.setAction(Intent.ACTION_GET_CONTENT); 
startActivityForResult(Intent.createChooser(intent, "Select Picture"), Constants.SELECT_PICTURE); 

而就OnActivityResult()的代码是

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    if(requestCode==Constants.SELECT_PICTURE && resultCode==RESULT_OK && null!=data) { 
     Uri uri=data.getData(); 
     Picasso.with(UsersProfileActivity.this) 
      .load(uri) 
      .centerCrop() 
      .resize(200,200) 
      .into(img_photo); 

     // This profile image i am storing into a sharedpreference   
     profile_image=uri.toString(); 
    } 

虽然从sharedprefrence检索我用字符串转换为URI Uri.parse(profile_image)

但是,如果我注意到,uri返回不同的android手机如下

Mi(Lollipop)- Uri=content://media/external/images/media/12415 
samsung(KitKat)-Uri=content://media/external/images/media/786 
Motorola(Marshmallow)- Uri=content://com.android.providers.media.documents/document/image%3A30731 
One Plus One (Marshmallow)- Uri=content://com.android.providers.media.documents/document/image%3A475 

因此,当URI内容-content://媒体/外部/图像/媒体/是ImageView的完美显示图像而在其他情况下,没有

+1

我想它的android 6.0权限的事情,检查如果你正在处理''in运行时棉花糖版本。 – SripadRaj

+0

nope我alreday检查了那些东西,甚至发生在一些设备上的较低的Android版本 – abh22ishek

+0

您使用的是什么版本的毕加索? – JohnWowUs

试试这个

我开发和tested和工作

  1. 联想K3注(棉花糖)
  2. 摩托罗拉(棒棒堂)
  3. 三星(奇巧)

在你MainActivity.java添加

profilePicture = (ImageView)findViewById(R.id.imgProfilePicture); 
    sharedPreferences = getSharedPreferences(getString(R.string.app_name)+"_ProfileDetails",MODE_PRIVATE); 

    // get uri from shared preference 
    String profilePicUri = sharedPreferences.getString("profilePicUrl",""); 

    // if uri not found 
    if (profilePicUri.equalsIgnoreCase("")){ 
     // code for open gallery to select image 
     Intent intent; 
     if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ 
      intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); 
      intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); 
      intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); 
     }else{ 
      intent = new Intent(Intent.ACTION_GET_CONTENT); 
     } 
     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); 
     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
     intent.setType("image/*"); 

     startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE_CONSTANT); 
    }else{ 
     try{ 
      final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION 
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
      // Check for the freshest data. 
      getContentResolver().takePersistableUriPermission(Uri.parse(profilePicUri), takeFlags); 
      // convert uri to bitmap 
      Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), Uri.parse(profilePicUri)); 
      // set bitmap to imageview 
      profilePicture.setImageBitmap(bitmap); 
     } 
     catch (Exception e){ 
      //handle exception 
      e.printStackTrace(); 
     } 
    } 

现在处理onActivityResult

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 
    if (requestCode == SELECT_PICTURE_CONSTANT && resultCode == RESULT_OK && null != data) { 
     Uri uri = data.getData(); 
     // This profile image i am storing into a sharedpreference 
     SharedPreferences.Editor editor = sharedPreferences.edit(); 
     // save uri to shared preference 
     editor.putString("profilePicUrl",uri.toString()); 
     editor.commit(); 
     profilePicture.setImageURI(uri); 
    } 
} 

在你Manifest文件中添加permission

<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 

注:

Assuming您添加代码take permissionMarshmallow

Resul牛逼Uri

联想K3注:content://com.android.externalstorage.documents/document/primary%3ADCIM%2FCamera%2FIMG_20160606_212815.jpg

三星:content://com.android.providers.media.documents/document/image%3A2086

摩托罗拉:content://com.android.providers.media.documents/document/image%3A15828

+0

你能告诉我所有三种设备的uri吗? – abh22ishek

+0

你能检查一件事吗?当你存储在sharedprefrence中时,关闭你的应用程序后,确保活动被android杀死,即按下hone按钮并杀死这个应用程序。然后你打开这个应用程序,并检查图像是否存在 – abh22ishek

+0

是的,我按Home按钮,然后从最近的应用程序列表中杀了应用程序....这是我测试它的工作..... –

您需要申请许可才能阅读外部存储用户在运行时为Android 6+

https://developer.android.com/training/permissions/requesting.html#perm-check

希望这有助于。

+0

运行时权限是必需的android棉花糖,但在这种情况下,我不阅读或写在设备的内部storage.And我不认为你需要从写权限和阅读sharedprefrences文件 – abh22ishek

+0

但你不保存文件,Uri只包含文件的路径,所以你需要权限才能读取路径 – Vlad

+0

的内容其实我正在转换Uri tio字符串,然后存储在sharedPreference中,所以它只会作为一个字符串或路径? – abh22ishek

也许你可以通过首先将URI转换为真实路径来处理它。

public String getRealPathFromURI(Context context, Uri contentUri) { 
    Cursor cursor = null; 
    try { 
     String[] proj = { MediaStore.Images.Media.DATA }; 
     cursor = context.getContentResolver().query(contentUri, proj, null, null, null); 
     int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
     cursor.moveToFirst(); 
     return cursor.getString(column_index); 
    } finally { 
     if (cursor != null) { 
      cursor.close(); 
     } 
    } 
} 

而且你的onActivityResult应该看起来像这样

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    if(requestCode==Constants.SELECT_PICTURE && resultCode==RESULT_OK && null!=data) 
    { 
     Uri uri=data.getData(); 
     String imagePath = getRealPathFromURI(getApplicationContext(), uril); 
Picasso.with(UsersProfileActivity.this).load(imagePath).centerCrop().resize(200,200).into(img_photo); 

    profile_image = imagePath; 

    } 
+0

我已经试过了,doesn 't工作 – abh22ishek

我已成功地做到这一点过去。而不是将其存储在SharePreferences中,而是在onSaveInstanceState(Bundle)被bundle.putParcelable(SOME_KEY,uri)调用时将其保存在Bundle中。你可以这样做,因为Uri实现了Parcelable。 之后,检查通过onCreate()传递的Bundle中的这个uri。 代码:

public void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 
    if (savedInstanceState != null){ 
     loadImage((Uri)saveInstanceState.getParcelable(SOME_KEY)) 
    } 
} 

public void onSaveInstanceState(Bundle bundle){ 
    bundle.putParcelable(SOME_KEY, uri) 
} 

P/S:我想存储SharePreference URI的问题是编码/解码URI。

4.4 API overview报价:

“在Android的早期版本中,如果你希望你的应用程序从另一个应用程序检索特定类型的文件,则必须调用与ACTION_GET_CONTENT行动的意图。此动作仍然是向您的应用程序请求要将文件导入的适当方式。但是,Android 4。4引入了ACTION_OPEN_DOCUMENT行动,它允许用户选择特定类型的文件,并授予您的应用程序的长期读取访问该文件(可能有写权限),而不用导入文件到您的应用程序。 “(强调)

为了让您的应用检索先前选择的图像,刚刚从ACTION_GET_CONTENT改变行动ACTION_OPEN_DOCUMENT(溶液证实工作的Nexus 7 2013)。

Intent intent = new Intent(); 
    intent.setType("image/*"); 
    String action = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_GET_CONTENT; 
    intent.setAction(action); 
    startActivityForResult(Intent.createChooser(intent, "Select Picture"), Constants.SELECT_PICTURE); 
+0

我试过了,不起作用 – abh22ishek

您可以轻松地转换URI为位图:

ParcelFileDescriptor parcelFileDescriptor = 
       context.getContentResolver().openFileDescriptor(selectedFileUri, "r"); 
     FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); 
     Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); 


     parcelFileDescriptor.close(); 

然后在设定的ImageView:imgview.setImageBitmap(图像);

希望这会帮助你。

可能是毕加索版本控制问题。他们修正了在2.5.0(2.4.0 ...?)版本中加载大图片的情况,这些图片还没有通过存储库提供。

您需要手动包含毕加索的夜间快照,这可能会解决您的问题。它为我做了。

+0

它没有问题的毕加索我认为,因为当我关闭我的应用程序,然后我打开它,毕加索能够得到uri和显示在ImageView上,它不能显示只有当活动被破坏,其中包含我的问题中提到的路径的imageview – abh22ishek

+0

好吧,然后签出我的答案,保存实例状态。 –

您通过URI在这个方法中它会返回一个字符串,比其转换成位图

String path = getPath(getApplicationContext(), uri); 
    Bitmap bitmap = BitmapFactory.decodeFile(path); 
    imageView.setImageBitmap(bitmap); 





public static String getPath(final Context context, final Uri uri) { 

    // DocumentProvider 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { 

     if (isExternalStorageDocument(uri)) {// ExternalStorageProvider 
      final String docId = DocumentsContract.getDocumentId(uri); 
      final String[] split = docId.split(":"); 
      final String type = split[0]; 
      String storageDefinition; 


      if ("primary".equalsIgnoreCase(type)) { 

       return Environment.getExternalStorageDirectory() + "/" + split[1]; 

      } else { 

       if (Environment.isExternalStorageRemovable()) { 
        storageDefinition = "EXTERNAL_STORAGE"; 

       } else { 
        storageDefinition = "SECONDARY_STORAGE"; 
       } 

       return System.getenv(storageDefinition) + "/" + split[1]; 
      } 

     } else if (isDownloadsDocument(uri)) {// DownloadsProvider 

      final String id = DocumentsContract.getDocumentId(uri); 
      final Uri contentUri = ContentUris.withAppendedId(
        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); 

      return getDataColumn(context, contentUri, null, null); 

     } else if (isMediaDocument(uri)) {// MediaProvider 
      final String docId = DocumentsContract.getDocumentId(uri); 
      final String[] split = docId.split(":"); 
      final String type = split[0]; 

      Uri contentUri = null; 
      if ("image".equals(type)) { 
       contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 
      } else if ("video".equals(type)) { 
       contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 
      } else if ("audio".equals(type)) { 
       contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 
      } 

      final String selection = "_id=?"; 
      final String[] selectionArgs = new String[]{ 
        split[1] 
      }; 

      return getDataColumn(context, contentUri, selection, selectionArgs); 
     } 

    } else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general) 

     // Return the remote address 
     if (isGooglePhotosUri(uri)) 
      return uri.getLastPathSegment(); 

     return getDataColumn(context, uri, null, null); 

    } else if ("file".equalsIgnoreCase(uri.getScheme())) {// File 
     return uri.getPath(); 
    } 

    return null; 
} 

我也碰到这样的事情早,发现了一个有用的辅助类,让你的文件的确切位置。 这是link

您可以使用FileUtils.getPath(context,uri)或FileUtils.getFile(context,uri)等方法来获取文件。然后就像这样使用它:

Picasso.with(UsersProfileActivity.this) 
     .load(Uri.fromFile(file)) 
     .centerCrop() 
     .resize(200,200) 
     .into(img_photo); 

希望这会有所帮助。

只是不是100%确定,如果我得到的问题。如果某些图像无法在imageView中显示(甚至在关闭并重新启动应用程序之前),那么问题在于毕加索能够处理来自某些提供商的内容。我不明白事实如此,但如果是这样,那么您可能会考虑为该库提交一个bug/RFE。另一方面,如果毕加索能正确显示给定Uri的图像,而不是在Uri_org - > String - > Uri_regen转换之后显示,则意味着Uri_org与Uri_regen不同。您可以(暂时)添加几行代码将字符串转换回Uri,并在后面放置一个断点并比较两个Uri。这应该让你知道事情是怎么回事。

profile_image=uri.toString(); 
//add the next few lines for debugging purposes only; remove them later 
Uri uri2 = Uri.parse(profile_image) 
if (!uri.equals(uri2) 
    //add a breakpoint on the next line 
    Log.d("Uri mismatch), "Ouch"); 
//remove the lines after you are done with debugging 

如果你不打断点,那么断点移回“if”语句和目视检查两个的URI(这几乎可以肯定将是相同的,否则你会击中了断点,但是这有助于检查调试代码本身)。如果Uri是相同的,那么String偏好由于某种原因不能正确保存。在这种情况下,请记下原始的URI,并在该字符串转换回乌里行添加一个断点:

Uri uri = Uri.parse(profile_image) //profile_image is retrieved from sharedpreferences 

如果前面的实验工作,应该在这里再次除非profile_image是不同的工作。无论哪种方式,你应该指出问题的出处。

祝你好运!

我觉得与图像文件的URI的问题,我使用一个类来获取确切的URI,并且它已经过测试并在所有版本上工作。

package fandooo.com.fandooo.util; 

import android.content.ContentUris; 
import android.content.Context; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Build; 
import android.os.Environment; 
import android.provider.DocumentsContract; 
import android.provider.MediaStore; 

public class ImageFilePath { 

    /** 
    * Method for return file path of Gallery image 
    * 
    * @param context 
    * @param uri 
    * @return path of the selected image file from gallery 
    */ 
    public static String getPath(final Context context, final Uri uri) { 

     // check here to KITKAT or new version 
     final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 

     // DocumentProvider 
     if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { 

      // ExternalStorageProvider 
      if (isExternalStorageDocument(uri)) { 
       final String docId = DocumentsContract.getDocumentId(uri); 
       final String[] split = docId.split(":"); 
       final String type = split[0]; 

       if ("primary".equalsIgnoreCase(type)) { 
        return Environment.getExternalStorageDirectory() + "/" 
          + split[1]; 
       } 
      } 
      // DownloadsProvider 
      else if (isDownloadsDocument(uri)) { 

       final String id = DocumentsContract.getDocumentId(uri); 
       final Uri contentUri = ContentUris.withAppendedId(
         Uri.parse("content://downloads/public_downloads"), 
         Long.valueOf(id)); 

       return getDataColumn(context, contentUri, null, null); 
      } 
      // MediaProvider 
      else if (isMediaDocument(uri)) { 
       final String docId = DocumentsContract.getDocumentId(uri); 
       final String[] split = docId.split(":"); 
       final String type = split[0]; 

       Uri contentUri = null; 
       if ("image".equals(type)) { 
        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 
       } else if ("video".equals(type)) { 
        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 
       } else if ("audio".equals(type)) { 
        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 
       } 

       final String selection = "_id=?"; 
       final String[] selectionArgs = new String[] { split[1] }; 

       return getDataColumn(context, contentUri, selection, 
         selectionArgs); 
      } 
     } 
     // MediaStore (and general) 
     else if ("content".equalsIgnoreCase(uri.getScheme())) { 

      // Return the remote address 
      if (isGooglePhotosUri(uri)) 
       return uri.getLastPathSegment(); 

      return getDataColumn(context, uri, null, null); 
     } 
     // File 
     else if ("file".equalsIgnoreCase(uri.getScheme())) { 
      return uri.getPath(); 
     } 

     return null; 
    } 

    /** 
    * Get the value of the data column for this Uri. This is useful for 
    * MediaStore Uris, and other file-based ContentProviders. 
    * 
    * @param context 
    *   The context. 
    * @param uri 
    *   The Uri to query. 
    * @param selection 
    *   (Optional) Filter used in the query. 
    * @param selectionArgs 
    *   (Optional) Selection arguments used in the query. 
    * @return The value of the _data column, which is typically a file path. 
    */ 
    public static String getDataColumn(Context context, Uri uri, 
             String selection, String[] selectionArgs) { 

     Cursor cursor = null; 
     final String column = "_data"; 
     final String[] projection = { column }; 

     try { 
      cursor = context.getContentResolver().query(uri, projection, 
        selection, selectionArgs, null); 
      if (cursor != null && cursor.moveToFirst()) { 
       final int index = cursor.getColumnIndexOrThrow(column); 
       return cursor.getString(index); 
      } 
     } finally { 
      if (cursor != null) 
       cursor.close(); 
     } 
     return null; 
    } 

    /** 
    * @param uri 
    *   The Uri to check. 
    * @return Whether the Uri authority is ExternalStorageProvider. 
    */ 
    public static boolean isExternalStorageDocument(Uri uri) { 
     return "com.android.externalstorage.documents".equals(uri 
       .getAuthority()); 
    } 

    /** 
    * @param uri 
    *   The Uri to check. 
    * @return Whether the Uri authority is DownloadsProvider. 
    */ 
    public static boolean isDownloadsDocument(Uri uri) { 
     return "com.android.providers.downloads.documents".equals(uri 
       .getAuthority()); 
    } 

    /** 
    * @param uri 
    *   The Uri to check. 
    * @return Whether the Uri authority is MediaProvider. 
    */ 
    public static boolean isMediaDocument(Uri uri) { 
     return "com.android.providers.media.documents".equals(uri 
       .getAuthority()); 
    } 

    /** 
    * @param uri 
    *   The Uri to check. 
    * @return Whether the Uri authority is Google Photos. 
    */ 
    public static boolean isGooglePhotosUri(Uri uri) { 
     return "com.google.android.apps.photos.content".equals(uri 
       .getAuthority()); 
    } 
} 

使用getPath来查找文件的确切路径。这是处理您定义的问题的最简单方法。请尝试让我知道如果你需要进一步的援助:)

+1

它需要Build.VERSION.SDK_INT> = 19,但它的工作原理! – djdance

+1

这节省了我的时间。谢谢Neo – RameshJaga