android obtenir le chemin réel par Uri.getPath ()

107

J'essaye d'obtenir l'image de la galerie.

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode );

Après mon retour de cette activité, j'ai une donnée, qui contient Uri. On dirait:

content://media/external/images/1

Comment puis-je convertir ce chemin en un vrai (comme ' /sdcard/image.png')?

Merci

Davs
la source
1
C'est évidemment un commentaire très tardif, mais je voulais juste souligner que la méthode startActivityForResultCode prend un code de requête comme argument, pas un code de résultat.
Tianxiang Xiong
ne vous uri.getPath()a pas donné de vrai chemin?
Darpan
#Try This Still, si vous rencontrez le problème pour obtenir le vrai chemin, vous pouvez essayer mes réponses. Les réponses ci-dessus ne m'ont pas aidé. Explication : - Cette méthode obtient l'URI, puis vérifie le niveau d'API de votre appareil Android après cela, en fonction du niveau d'API, elle générera le chemin réel. Le code pour générer un chemin réel est différent selon les niveaux d'API. Voici ma réponse
Sunil

Réponses:

56

Est-il vraiment nécessaire pour vous d'obtenir un chemin physique?
Par exemple, ImageView.setImageURI()et ContentResolver.openInputStream()vous permettent d'accéder au contenu d'un fichier sans connaître son chemin réel.

molnarm
la source
C'est exactement ce que j'ai cherché, mais je n'ai pas pu trouver. Merci.
davs
6
Désolé et si je veux convertir cette image en fichier, sans obtenir le vrai chemin, comment le faire?
Chlebta
6
Le chemin physique donne accès au nom de fichier et à l'extension. En cas de téléchargement de fichiers.
Clocker
195

C'est ce que je fais:

Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));

et:

private String getRealPathFromURI(Uri contentURI) {
    String result;
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) { // Source is Dropbox or other similar local file path
        result = contentURI.getPath();
    } else { 
        cursor.moveToFirst(); 
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}

REMARQUE: la managedQuery()méthode est obsolète, je ne l'utilise donc pas.

Dernière modification: amélioration. Nous devrions fermer le curseur !!

cesards
la source
1
stackoverflow.com/a/7265235/375093 C'est une autre option, mais suggérée comme meilleure que ci-dessus. Vérifiez-le aussi
Sundeep
6
Salut @ m3n0R, Dans Moto G, la colonne MediaStore.Images.ImageColumns.DATA n'existe pas du tout. Comment obtenir une image sans cette colonne?
seema
16
ERREUR Assurez-vous que le curseur est correctement initialisé avant d'accéder aux données à partir de celui-ci.
Enregistrement
1
@ReneJuuse: Excellente ressource. J'ai finalement réussi à résoudre ce problème grâce à cela - je ne savais pas qu'il y avait autant de changements depuis la création d'Android. J'utilisais l'API 21 et lorsque j'ai utilisé l'implémentation de l'API 19 affichée sur le site que vous avez lié, cela a finalement fonctionné.
Milos Ivanovic
2
Impossible de lire la ligne 0, col -1 à partir de CursorWindow. Assurez-vous que le curseur est correctement initialisé avant d'accéder à ses données.
Maveň ツ
18

@Rene Juuse - ci-dessus dans les commentaires ... Merci pour ce lien!

. le code pour obtenir le chemin réel est un peu différent d'un SDK à l'autre, nous avons donc ci-dessous trois méthodes qui traitent différents SDK.

getRealPathFromURI_API19 (): renvoie le chemin réel pour l'API 19 (ou supérieur mais non testé) getRealPathFromURI_API11to18 (): renvoie le chemin réel de l'API 11 vers l'API 18 getRealPathFromURI_below11 (): renvoie le chemin réel de l'API inférieur à 11

public class RealPathUtil {

@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
    String filePath = "";
    String wholeID = DocumentsContract.getDocumentId(uri);

     // Split at colon, use second item in the array
     String id = wholeID.split(":")[1];

     String[] column = { MediaStore.Images.Media.DATA };     

     // where id is equal to             
     String sel = MediaStore.Images.Media._ID + "=?";

     Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                               column, sel, new String[]{ id }, null);

     int columnIndex = cursor.getColumnIndex(column[0]);

     if (cursor.moveToFirst()) {
         filePath = cursor.getString(columnIndex);
     }   
     cursor.close();
     return filePath;
}


@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
      String[] proj = { MediaStore.Images.Media.DATA };
      String result = null;

      CursorLoader cursorLoader = new CursorLoader(
              context, 
        contentUri, proj, null, null, null);        
      Cursor cursor = cursorLoader.loadInBackground();

      if(cursor != null){
       int column_index = 
         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       result = cursor.getString(column_index);
      }
      return result;  
}

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
           String[] proj = { MediaStore.Images.Media.DATA };
           Cursor 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);
}

police: http://hmkcode.com/android-display-selected-image-and-its-real-path/


MISE À JOUR 2016 Mars

Pour résoudre tous les problèmes avec le chemin des images, j'essaie de créer une galerie personnalisée en tant que Facebook et d'autres applications. C'est parce que vous pouvez utiliser uniquement des fichiers locaux (fichiers réels, pas virtuels ou temporaires), je résous tous les problèmes avec cette bibliothèque.

https://github.com/nohana/Laevatein (cette bibliothèque consiste à prendre une photo de l'appareil photo ou à choisir dans la galerie, si vous choisissez dans la galerie, il a un tiroir avec des albums et affiche simplement les fichiers locaux)

luizfelipetx
la source
@Clocker sur Samsung S4 ni
Ricardo
Im vraiment difficile de gérer tous les types d'images source dans Android. Si vous téléchargez ou choisissez parmi une galerie, la meilleure solution est de créer une galerie à partir de Facebook. C'est une galerie personnalisée avec juste des images réelles dans l'appareil, pas virtuelles ou temporaires. Je résout tous les problèmes de mon application en utilisant cette bibliothèque. github.com/nohana/Laevatein Sa très bonne bibliothèque. Personnaliser n'est pas simple, mais vous pouvez ouvrir le code et apporter vos modifications. J'espère que cela pourra vous aider.
luizfelipetx
Cassé sur mon Samsung S2 avec 4.4.1
Oliver Dixon
J'ai besoin d'obtenir les fichiers comme pdf ou doc, je ne parviens pas à obtenir le chemin. Pouvez-vous m'aider s'il vous plaît?
Anish Kumar le
1
Impressionnant! Enfin quelque chose qui fonctionne vraiment. Je cherchais ça depuis longtemps. Merci.
Javatar
14

Remarque Il s'agit d'une amélioration de la réponse @ user3516549 et je l'ai vérifiée sur Moto G3 avec Android 6.0.1
J'ai ce problème, j'ai donc essayé la réponse de @ user3516549 mais dans certains cas, cela ne fonctionnait pas correctement. J'ai constaté que dans Android 6.0 (ou supérieur), lorsque nous démarrons l'intention de sélection d'image de la galerie, un écran s'ouvre et affiche des images récentes lorsque l'utilisateur sélectionne l'image dans cette liste, nous obtiendrons l'URI

content://com.android.providers.media.documents/document/image%3A52530

tandis que si l'utilisateur sélectionne la galerie dans le tiroir coulissant au lieu de la récente, nous obtiendrons l'URI comme

content://media/external/images/media/52530

Alors je l'ai manipulé getRealPathFromURI_API19()

public static String getRealPathFromURI_API19(Context context, Uri uri) {
        String filePath = "";
        if (uri.getHost().contains("com.android.providers.media")) {
            // Image pick from recent 
            String wholeID = DocumentsContract.getDocumentId(uri);

            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];

            String[] column = {MediaStore.Images.Media.DATA};

            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";

            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{id}, null);

            int columnIndex = cursor.getColumnIndex(column[0]);

            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();
            return filePath;
        } else {
            // image pick from gallery 
           return  getRealPathFromURI_BelowAPI11(context,uri)
        }

    }

EDIT: si vous essayez d'obtenir le chemin de l'image du fichier dans la carte SD externe dans la version supérieure, vérifiez ma question

Jaiprakash Soni
la source
Salut ami, oui c'est vrai. mais cela se produit parce que maintenant, Google a un format par défaut pour télécharger toutes les photos de votre téléphone vers Google Docs. Et enregistrez simplement la vignette dans votre téléphone. Si vous obtenez cet uri de Google Docs, vous devez télécharger la photo avant de l'utiliser. Ce n'est pas bon en général. Donc, pour résoudre tous les problèmes ici, j'utilise maintenant cette bibliothèque. (cette bibliothèque utilise simplement des fichiers locaux, et avec cette solution vos problèmes seront résolus), ou vous pouvez extraire le code de la bibliothèque et vous améliorer pour répondre à votre problème. github.com/nohana/Laevatein J'espère que cela peut vous aider.
luizfelipetx
1+, son travail parfait pour moi. Comme @JaiprakasSoni l'a dit dans sa réponse, j'ai rencontré le même problème lorsque j'exécute mon application dans le jeu Moto G4, mais lorsque j'utilise le code ci-dessus, cela fonctionne bien pour moi. Merci. Vous économisez mon temps
Shailesh
6

EDIT: Utilisez cette solution ici: https://stackoverflow.com/a/20559175/2033223 Fonctionne parfaitement!

Tout d'abord, merci pour votre solution @luizfelipetx

J'ai un peu changé votre solution. Cela fonctionne pour moi:

public static String getRealPathFromDocumentUri(Context context, Uri uri){
    String filePath = "";

    Pattern p = Pattern.compile("(\\d+)$");
    Matcher m = p.matcher(uri.toString());
    if (!m.find()) {
        Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString());
        return filePath;
    }
    String imgId = m.group();

    String[] column = { MediaStore.Images.Media.DATA };
    String sel = MediaStore.Images.Media._ID + "=?";

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            column, sel, new String[]{ imgId }, null);

    int columnIndex = cursor.getColumnIndex(column[0]);

    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }
    cursor.close();

    return filePath;
}

Remarque: nous avons donc des documents et une image, selon que l'image provient de 'recents', 'gallery' ou quoi que ce soit d'autre. J'extraye donc d'abord l'ID de l'image avant de la rechercher.

Javatar
la source
1

Hii voici mon code complet pour prendre des images depuis un appareil photo ou une galerie

// Ma déclaration de variable

protected static final int CAMERA_REQUEST = 0;
    protected static final int GALLERY_REQUEST = 1;
    Bitmap bitmap;
    Uri uri;
    Intent picIntent = null;

//Sur clic

if (v.getId()==R.id.image_id){
            startDilog();
        }

// corps de la méthode

private void startDilog() {
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this);
    myAlertDilog.setTitle("Upload picture option..");
    myAlertDilog.setMessage("Where to upload picture????");
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(Intent.ACTION_GET_CONTENT,null);
            picIntent.setType("image/*");
            picIntent.putExtra("return_data",true);
            startActivityForResult(picIntent,GALLERY_REQUEST);
        }
    });
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(picIntent,CAMERA_REQUEST);
        }
    });
    myAlertDilog.show();
}

// Et le reste des choses

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==GALLERY_REQUEST){
        if (resultCode==RESULT_OK){
            if (data!=null) {
                uri = data.getData();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                try {
                    BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    options.inSampleSize = calculateInSampleSize(options, 100, 100);
                    options.inJustDecodeBounds = false;
                    Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    imageofpic.setImageBitmap(image);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        }else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            if (data.hasExtra("data")) {
                bitmap = (Bitmap) data.getExtras().get("data");
                uri = getImageUri(YourActivity.this,bitmap);
                File finalFile = new File(getRealPathFromUri(uri));
                imageofpic.setImageBitmap(bitmap);
            } else if (data.getExtras() == null) {

                Toast.makeText(getApplicationContext(),
                        "No extras to retrieve!", Toast.LENGTH_SHORT)
                        .show();

                BitmapDrawable thumbnail = new BitmapDrawable(
                        getResources(), data.getData().getPath());
                pet_pic.setImageDrawable(thumbnail);

            }

        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private String getRealPathFromUri(Uri tempUri) {
    Cursor cursor = null;
    try {
        String[] proj = { MediaStore.Images.Media.DATA };
        cursor = this.getContentResolver().query(tempUri,  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();
        }
    }
}
public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

private Uri getImageUri(YourActivity youractivity, Bitmap bitmap) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null);
    return Uri.parse(path);
}
Tanmay Sahoo
la source
Comment vous savez est 100 dans cette ligne options.inSampleSize = calculateInSampleSize(options, 100, 100);
John Joe