android pobierz prawdziwą ścieżkę przez Uri.getPath ()


107

Próbuję pobrać obraz z galerii.

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

Po powrocie z tego działania mam dane, które zawierają Uri. To wygląda jak:

content://media/external/images/1

Jak mogę przekonwertować tę ścieżkę na prawdziwą (tak jak „ /sdcard/image.png”)?

Dzięki


1
Jest to oczywiście bardzo późny komentarz, ale chciałem tylko zaznaczyć, że metoda startActivityForResultCode przyjmuje kod żądania jako argument, a nie kod wynikowy.
Tianxiang Xiong

nie uri.getPath()nie daje prawdziwą ścieżkę?
Darpan,

# Spróbuj tego Jeśli napotkasz problem, aby znaleźć prawdziwą ścieżkę, możesz wypróbować moje odpowiedzi. Powyższe odpowiedzi mi nie pomogły. Objaśnienie : - Ta metoda pobiera identyfikator URI, a następnie sprawdza poziom interfejsu API urządzenia z systemem Android, a następnie zgodnie z poziomem interfejsu API wygeneruje rzeczywistą ścieżkę. Kod do generowania rzeczywistej ścieżki różni się w zależności od poziomów API. Oto moja odpowiedź
Sunil

Odpowiedzi:


56

Czy naprawdę musisz mieć fizyczną ścieżkę?
Na przykład ImageView.setImageURI()i ContentResolver.openInputStream()umożliwia dostęp do zawartości pliku bez znajomości jego prawdziwej ścieżki.


To jest dokładnie to, czego szukałem, ale nie mogłem znaleźć. Dzięki.
davs

6
Przepraszam i jeśli chcę przekonwertować ten obraz do pliku bez uzyskania prawdziwej ścieżki, jak to zrobić?
Chlebta

6
Ścieżka fizyczna daje dostęp do nazwy pliku i rozszerzenia. W przypadku przesyłania plików.
Clocker

195

Tym się właśnie zajmuję:

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

i:

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

UWAGA: managedQuery()metoda jest przestarzała, więc jej nie używam.

Ostatnia edycja: ulepszenie. Powinniśmy zamknąć kursor !!


1
stackoverflow.com/a/7265235/375093 Jest to inna opcja, ale sugerowana jako lepsza niż powyżej. Zobacz też
Sundeep

6
Cześć @ m3n0R, W Moto G kolumna MediaStore.Images.ImageColumns.DATA w ogóle nie istnieje. Jak uzyskać obraz bez tej kolumny?
wydaje się

16
BŁĄD Upewnij się, że kursor został poprawnie zainicjowany przed uzyskaniem dostępu do danych z niego .. sprawdzanie w API 19
Mayur R. Amipara

1
@ReneJuuse: Doskonały zasób. Dzięki temu wreszcie udało mi się rozwiązać ten problem - nie zdawałem sobie sprawy, że tyle zmian było od czasu powstania Androida. Używałem API 21 i kiedy użyłem implementacji API 19 pokazanej na stronie, do której jesteś podłączony, w końcu zadziałało.
Milos Ivanovic

2
Nie można odczytać wiersza 0, kolumna -1 z CursorWindow. Upewnij się, że kursor został poprawnie zainicjowany przed uzyskaniem z niego dostępu do danych.
Maveň ツ

18

@Rene Juuse - powyżej w komentarzach ... Dzięki za ten link!

. kod umożliwiający uzyskanie rzeczywistej ścieżki jest nieco inny w przypadku różnych zestawów SDK, więc poniżej mamy trzy metody, które obsługują różne zestawy SDK.

getRealPathFromURI_API19 (): zwraca rzeczywistą ścieżkę dla API 19 (lub nowszego, ale nie testowane) getRealPathFromURI_API11to18 (): zwraca rzeczywistą ścieżkę dla API 11 do API 18 getRealPathFromURI_below11 (): zwraca rzeczywistą ścieżkę dla API poniżej 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);
}

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


UPDATE 2016 marzec

Aby naprawić wszystkie problemy ze ścieżką obrazów, próbuję utworzyć niestandardową galerię jako Facebook i inne aplikacje. Dzieje się tak, ponieważ możesz używać tylko plików lokalnych (prawdziwych plików, a nie wirtualnych lub tymczasowych), rozwiązuję wszystkie problemy z tą biblioteką.

https://github.com/nohana/Laevatein (ta biblioteka ma zrobić zdjęcie z aparatu lub wybrać z galerii, jeśli wybierzesz z galerii ma szufladę z albumami i po prostu pokaż pliki lokalne)


@Clocker na Samsung S4 ani
Ricardo

Naprawdę trudno mi zarządzać wszystkimi typami obrazów źródłowych w systemie Android. Jeśli załadujesz lub wybierzesz galerię, najlepszym rozwiązaniem jest utworzenie galerii z facebooka. Jest to niestandardowa galeria z prawdziwymi obrazami w urządzeniu, bez wirtualnych ani tymczasowych. Naprawiam wszystkie problemy w mojej aplikacji przy użyciu tej biblioteki. github.com/nohana/Laevatein To naprawdę dobra biblioteka. Dostosowywanie nie jest proste, ale możesz otworzyć kod i wprowadzić zmiany. Mam nadzieję, że to ci pomoże.
luizfelipetx

Zepsuty na moim Samsungu S2 z 4.4.1
Oliver Dixon

Potrzebuję plików takich jak pdf lub doc, nie mogę znaleźć ścieżki. Możesz mi pomóc?
Anish Kumar

1
Niesamowite! Wreszcie coś, co naprawdę działa. Szukałem tego przez długi czas. Dzięki.
Javatar

14

Uwaga To jest poprawa w odpowiedzi @ user3516549 i sprawdziłem to na Moto G3 z Androidem 6.0.1
Mam ten problem, więc próbowałem odpowiedzieć @ user3516549, ale w niektórych przypadkach nie działała poprawnie. Zauważyłem, że w systemie Android 6.0 (lub nowszym), kiedy zaczynamy zamiar wyboru obrazu z galerii, otworzy się ekran pokazujący ostatnie obrazy, gdy użytkownik wybierze obraz z tej listy, otrzymamy uri jako

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

podczas gdy jeśli użytkownik wybierze galerię z wysuwanej szuflady zamiast ostatniej, otrzymamy uri jako

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

Więc załatwiłem to 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)
        }

    }

EDYCJA: jeśli próbujesz uzyskać ścieżkę obrazu do pliku na zewnętrznej karcie SD w wyższej wersji, sprawdź moje pytanie


Cześć przyjacielu, tak, to prawda. ale dzieje się tak, ponieważ teraz Google ma domyślny format przesyłania wszystkich zdjęć z telefonu do Google Docs. I po prostu zapisz miniaturę w telefonie. Jeśli otrzymasz ten identyfikator URI z Dokumentów Google, musisz pobrać zdjęcie przed jego użyciem. To ogólnie nie jest dobre. Tak więc, aby rozwiązać wszystkie problemy, teraz używam tej biblioteki. (ta biblioteka używa tylko plików lokalnych, a dzięki temu rozwiązaniu Twoje problemy zostaną rozwiązane) lub możesz wyodrębnić kod z biblioteki i poprawić się, aby rozwiązać problem. github.com/nohana/Laevatein Mam nadzieję, że to ci pomoże.
luizfelipetx

1+, jego praca jest dla mnie idealna. Jak @JaiprakasSoni powiedział w swojej odpowiedzi, napotkałem ten sam problem, gdy uruchamiam moją aplikację w grze Moto G4, ale kiedy używam powyższego kodu, działa to dobrze. Dzięki Ci. Oszczędzasz mój czas
Shailesh

6

EDYTUJ: Użyj tego rozwiązania tutaj: https://stackoverflow.com/a/20559175/2033223 Działa idealnie!

Po pierwsze, dziękuję za rozwiązanie @luizfelipetx

Trochę zmieniłem twoje rozwiązanie. To działa dla mnie:

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

Uwaga: otrzymaliśmy więc dokumenty i obraz, w zależności od tego, czy obraz pochodzi z „ostatnich”, „galerii” czy czegokolwiek. Więc najpierw wyodrębniam identyfikator obrazu, zanim go wyszukam.


1

Hii, oto mój kompletny kod do robienia zdjęć z kamery lub wichury

// Deklaracja mojej zmiennej

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

//Na kliknięcie

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

// treść metody

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

// I reszta

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

Skąd wiesz, to 100 w tej linii options.inSampleSize = calculateInSampleSize(options, 100, 100);
John Joe,

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.