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.