web-dev-qa-db-fra.com

Image uri n'affiche pas les images sur ImageView sur certains appareils Android.

J'ai un ImageView. Lorsque vous cliquez sur un ImageView, il ouvre la galerie et vous prenez une image et l'affichez sur ImageView. J'ai comme condition que, lorsque je ferme mon application et que je l'ouvre ensuite, l'image y sera conservée . Donc, pour cela, je stocke l'image Uri sur sharedprefrence . Uri et tente d'afficher l'image sur imageView.

Cependant, sur certains téléphones, l’image semble parfaite, comme Mi (Lollipop), Samsung (KitKat) Mais elle n’apparaît pas dans les téléphones de type Motorola, Marshmallow, One Plus One passe? Voici mon code

Pour ramasser une image que j'utilise 

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

Et sur le code OnActivityResult () est 

 @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();
     }

Et lors de la récupération de sharedprefrence, je convertis String en uri en utilisant Uri.parse(profile_image)

Cependant, si je remarque, les retours d'URI pour différents téléphones Android sont les suivants:

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

Par conséquent, lorsque le contenu d'URI est -content: // media/external/images/media/est l'image affichée sur ImageView Perfect et dans d'autres cas, ce n'est pas le cas.

14
abh22ishek

Essaye ça

J'ai développé et tested et travaille sur  

  1. Lenovo K3 Note (guimauve) 
  2. Motorola (sucette)
  3. Samsung (KitKat)

Dans votre MainActivity.Java ajouter

    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();
        }
    }

Maintenant gérer 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);
    }
}

Dans votre fichier Manifest, ajoutez 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" />

Remarque:  

Assuming vous avez ajouté du code pour take permission pour Marshmallow

Résultat Uri 

lenovo K3 Remarque: content://com.Android.externalstorage.documents/document/primary%3ADCIM%2FCamera%2FIMG_20160606_212815.jpg

samsung: content://com.Android.providers.media.documents/document/image%3A2086

Motorola: content://com.Android.providers.media.documents/document/image%3A15828

12
Pramod Waghmare

Je pense que le problème avec l'URI du fichier image, j'utilise une classe pour obtenir l'URI exacte, et il est testé et fonctionne sur toutes les versions.

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());
    }
}

Utilisez getPath pour trouver le chemin exact d'un fichier. C'est le moyen le plus simple de gérer le problème tel que vous l'avez défini. S'il vous plaît essayez de me le faire savoir si vous avez besoin d'aide supplémentaire :)

3
Neo

Citant de 4.4 Vue d'ensemble de l'API :

'Sur les versions précédentes d'Android, si vous souhaitez que votre application récupère un type de fichier spécifique à partir d'une autre application, elle doit invoquer une intention avec l'action ACTION_GET_CONTENT. Cette action reste le moyen approprié de demander le fichier que vous souhaitez importer dans votre application. Cependant, Android 4.4 introduit l'action ACTION_OPEN_DOCUMENT qui permet à l'utilisateur de sélectionner un fichier d'un type spécifique et de accorder à votre application un accès en lecture à long terme à ce fichier} _ ( éventuellement avec un accès en écriture) sans importer le fichier dans votre application. '(italiques ajoutés)

Pour permettre à votre application de récupérer des images précédemment sélectionnées, il suffit de changer l'action de ACTION_GET_CONTENT _ à ACTION_OPEN_DOCUMENT _ (la solution a été confirmée et fonctionne sur 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);
2
Kai

Passez votre URI dans cette méthode, elle retournera une chaîne et la convertira en bitmap

  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;
}
1
Tanveer Bulsari

Je me suis aussi heurté à quelque chose comme ceci plus tôt et ai trouvé une classe utile utile qui vous donne l'emplacement exact du fichier . Voici le link .

Vous pouvez utiliser des méthodes telles que FileUtils.getPath (context, uri) ou FileUtils.getFile (context, uri) pour obtenir le fichier. Ensuite, utilisez-le comme ceci:

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

J'espère que cela t'aides.

0
Siddharth jain

Mais je ne suis pas sûr à 100% si j'ai la question. Si certaines images ne peuvent pas être affichées dans l'imageView (même avant la fermeture et le redémarrage de l'application), le problème est que Picasso est capable de gérer le contenu de certains fournisseurs. Je n'ai pas l'impression que c'est le cas, mais si c'est le cas, vous voudrez peut-être envisager de déposer un bug/RFE pour cette bibliothèque. D'autre part, si Picasso affiche correctement l'image pour un Uri donné, mais pas après la conversion de Uri_org -> Chaîne -> Uri_regen, cela signifie que Uri_org n'est pas identique à Uri_regen. Vous pouvez (temporairement) ajouter quelques lignes à votre code pour reconvertir la chaîne en Uri et placer un point d'arrêt juste après et comparer les deux Uri. Cela devrait vous donner un indice sur la façon dont les choses vont mal.

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

Si vous n'atteignez pas le point d'arrêt, déplacez-le à la position "if" et vérifiez visuellement les deux Uri (qui seront presque certainement les mêmes, sinon vous auriez atteint le point d'arrêt, mais cela aiderait à vérifier le le code lui-même). Si les URI sont les mêmes, la préférence Chaîne n'est pas conservée correctement pour une raison quelconque. Dans ce cas, notez l'URI d'origine et ajoutez un point d'arrêt sur la ligne qui reconvertit la chaîne en Uri:

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

Si l'expérience précédente a fonctionné, il devrait fonctionner à nouveau ici à moins que profile_image ne soit différent. De toute façon, vous devriez avoir des indications sur le problème.

Bonne chance!

0
Kaamel

Peut-être que vous pouvez le gérer en convertissant d'abord l'URI en chemin réel.

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();
        }
    }
}

Et votre onActivityResult devrait ressembler à ceci

@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
ikhsan

Peut-être un problème de versioning de Picasso. Ils ont corrigé quelque chose avec le chargement d'images volumineuses dans la version 2.5.0 (2.4.0 ...?), Qui n'était pas encore disponible via les référentiels.

Vous devrez inclure manuellement l’instantané nocturne de Picasso, ce qui réglera probablement votre problème. Ça l'a fait pour moi.

0
Marc DiMillo

Vous pouvez facilement convertir une URI en Bitmap:

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


        parcelFileDescriptor.close();

Et puis définissez dans Imageview: imgview.setImageBitmap (image);

J'espère que ceci vous aidera.

0

Vous devez demander l'autorisation de lire le stockage externe à l'utilisateur lors de l'exécution pour Android 6+.

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

J'espère que cela t'aides.

0
Vlad

J'ai réussi à faire cela dans le passé. Au lieu de le stocker dans SharePreferences, je le sauvegarde dans le paquet lorsque onSaveInstanceState (Bundle) est appelé par: bundle.putParcelable (SOME_KEY, uri). Vous pouvez le faire car Uri implémente Parcelable. Après cela, vérifiez si cet uri dans le Bundle a été transmis à onCreate (). Code: 

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: Je suppose que le problème de stockage de l'URI dans SharePreference est le codage/décodage de l'URI.

0
Tin Tran