android ottiene il percorso reale da Uri.getPath ()


107

Sto cercando di ottenere un'immagine dalla galleria.

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

Dopo essere tornato da questa attività ho un dato, che contiene Uri. Sembra:

content://media/external/images/1

Come posso convertire questo percorso in uno reale (proprio come " /sdcard/image.png")?

Grazie


1
Questo è ovviamente un commento molto tardivo, ma volevo solo sottolineare che il metodo startActivityForResultCode accetta un codice di richiesta come argomento, non un codice di risultato.
Tianxiang Xiong

non uri.getPath()ti ha dato un vero percorso?
Darpan

# Prova ancora, se stai riscontrando il problema per ottenere il percorso reale, puoi provare le mie risposte. Le risposte sopra non mi hanno aiutato. Spiegazione : - Questo metodo ottiene l'URI e quindi controlla il livello API del tuo dispositivo Android, dopodiché in base al livello API genererà il percorso reale. Il codice per la generazione del percorso reale è diverso a seconda dei livelli API. Ecco la mia risposta
Sunil

Risposte:


56

È davvero necessario per te ottenere un percorso fisico?
Ad esempio, ImageView.setImageURI()e ContentResolver.openInputStream()consentono di accedere al contenuto di un file senza conoscerne il percorso reale.


È esattamente quello che ho cercato, ma non sono riuscito a trovare. Grazie.
davs

6
Scusa e se voglio convertire questa immagine in file, senza ottenere il percorso reale come si fa?
Chlebta

6
Il percorso fisico dà accesso al nome del file e all'estensione. In caso di caricamento di file.
Clocker

195

Questo è ciò che faccio:

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

e:

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

NOTA: il managedQuery()metodo è deprecato, quindi non lo sto usando.

Ultima modifica: miglioramento. Dobbiamo chiudere il cursore !!


1
stackoverflow.com/a/7265235/375093 Questa è un'altra opzione, ma suggerita come migliore di quella precedente. Dai un'occhiata anche a questo
Sundeep

6
Ciao @ m3n0R, In Moto G, la colonna MediaStore.Images.ImageColumns.DATA non esiste affatto. Come ottenere un'immagine senza questa colonna?
sembra il

16
ERRORE Assicurati che il Cursore sia inizializzato correttamente prima di accedere ai dati da esso .. controllo API 19
Mayur R. Amipara

1
@ReneJuuse: risorsa eccellente. Alla fine sono riuscito a risolvere questo problema grazie a ciò: non mi ero reso conto che ci fossero così tanti cambiamenti dall'inizio di Android. Stavo eseguendo l'API 21 e quando ho utilizzato l'implementazione dell'API 19 mostrata sul sito che hai collegato, finalmente ha funzionato.
Milos Ivanovic

2
Impossibile leggere la riga 0, col -1 da CursorWindow. Assicurarsi che il cursore sia inizializzato correttamente prima di accedere ai dati da esso.
Maveň ツ

18

@Rene Juuse - sopra nei commenti ... Grazie per questo link!

. il codice per ottenere il percorso reale è leggermente diverso da un SDK a un altro, quindi di seguito abbiamo tre metodi che si occupano di SDK diversi.

getRealPathFromURI_API19 (): restituisce il percorso reale per API 19 (o superiore ma non testato) getRealPathFromURI_API11to18 (): restituisce il percorso reale per API 11 all'API 18 getRealPathFromURI_below11 (): restituisce il percorso reale per API inferiore a 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);
}

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


AGGIORNAMENTO 2016 marzo

Per risolvere tutti i problemi con il percorso delle immagini provo a creare una galleria personalizzata come Facebook e altre app. Questo perché puoi usare solo file locali (file reali, non virtuali o temporanei), risolvo tutti i problemi con questa libreria.

https://github.com/nohana/Laevatein (questa libreria serve per scattare foto dalla fotocamera o scegliere dalla galleria, se scegli dalla galleria ha un cassetto con gli album e mostra solo i file locali)


@Clocker su Samsung S4 neanche
Ricardo

Sono davvero difficile gestire tutti i tipi di immagini sorgente in Android. Se carichi o scegli dalla galleria, la soluzione migliore è crearla come galleria da Facebook. È una galleria personalizzata con solo immagini reali nel dispositivo, non virtuali o temporanee. Risolvo tutti i problemi nella mia app usando questa libreria. github.com/nohana/Laevatein La sua libreria davvero buona. Personalizzare non è semplice, ma puoi aprire il codice e apportare le tue modifiche. Spero che ciò possa aiutarti.
luizfelipetx

Rotto sul mio Samsung S2 con 4.4.1
Oliver Dixon

Ho bisogno di ottenere i file come pdf o doc, non riesco a ottenere il percorso. Potete per favore aiutarmi?
Anish Kumar

1
Eccezionale! Finalmente qualcosa che funziona davvero. Lo stavo cercando da molto tempo. Grazie.
Javatar

14

Nota Questo è un miglioramento della risposta @ user3516549 e l'ho verificato su Moto G3 con Android 6.0.1
Ho questo problema, quindi ho provato a rispondere a @ user3516549 ma in alcuni casi non funzionava correttamente. Ho scoperto che in Android 6.0 (o versioni successive) quando iniziamo l'intento di selezione dell'immagine della galleria, si aprirà una schermata che mostra le immagini recenti quando l'utente seleziona l'immagine da questo elenco otterremo uri come

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

mentre se l'utente seleziona la galleria dal cassetto scorrevole anziché recente, otterremo uri come

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

Quindi devo gestirlo 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)
        }

    }

MODIFICA: se stai cercando di ottenere il percorso dell'immagine del file nella scheda SD esterna nella versione superiore, controlla la mia domanda


Ciao amico, sì, è vero. ma questo sta accadendo perché ora Google ha un formato predefinito per caricare tutte le foto dal tuo telefono a Google Docs. E salva la miniatura nel tuo telefono. Se ottieni questo uri da Google Docs, devi scaricare la foto prima di utilizzarlo. Questo non va bene in generale. Quindi, per risolvere tutti i problemi qui, ora sto usando questa libreria. (questa libreria usa solo file locali, e con questa soluzione i tuoi problemi saranno risolti), oppure puoi estrarre il codice dalla libreria e migliorare te stesso per affrontare il tuo problema. github.com/nohana/Laevatein Spero che questo possa aiutarti.
luizfelipetx

1+, è perfetto per me. Come ha detto @JaiprakasSoni nella sua risposta, ho riscontrato lo stesso problema quando eseguo la mia app in Moto G4, ma quando uso il codice sopra funziona bene per me. Grazie. Mi risparmi tempo
Shailesh

6

EDIT: Usa questa soluzione qui: https://stackoverflow.com/a/20559175/2033223 Funziona perfettamente!

Prima di tutto, grazie per la tua soluzione @luizfelipetx

Ho cambiato un po 'la tua soluzione. Questo funziona per me:

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

Nota: quindi abbiamo documenti e immagini, a seconda se l'immagine proviene da "recenti", "galleria" o altro. Quindi estraggo l'ID immagine prima di cercarlo.


1

Ciao, ecco il mio codice completo per scattare immagini dalla fotocamera o da una tempesta

// La mia dichiarazione di variabile

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

//Al clic

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

// corpo del metodo

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

// E il resto delle cose

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

Come sai che è 100 in questa riga options.inSampleSize = calculateInSampleSize(options, 100, 100);
John Joe

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.