android отримати реальний шлях від Uri.getPath ()


107

Я намагаюся отримати зображення з галереї.

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

Після того як я повернувся з цієї діяльності, у мене з’явилися дані, які містять Uri. Це виглядає як:

content://media/external/images/1

Як я можу перетворити цей шлях у справжній (подібно до ' /sdcard/image.png')?

Дякую


1
Це, очевидно, дуже пізній коментар, але я просто хотів зазначити, що метод startActivityForResultCode приймає код запиту як аргумент, а не код результату.
Tianxiang Xiong

нічого uri.getPath()не дасть вам реальний шлях?
Дарпан

# Спробуйте це все-таки, якщо у вас виникає проблема отримати реальний шлях, ви можете спробувати мої відповіді. Наведені вище відповіді не допомогли мені. Пояснення : - Цей метод отримує URI, а потім перевіряйте рівень API вашого пристрою Android після цього відповідно до рівня API, він генерує дійсний шлях. Код для генерації реального шляху відрізняється відповідно до рівнів API. Ось моя відповідь
Sunil

Відповіді:


56

Вам справді потрібно пройти фізичний шлях?
Наприклад, ImageView.setImageURI()і ContentResolver.openInputStream()дозволяють вам отримувати доступ до вмісту файлу, не знаючи його реального шляху.


Це саме те, що я шукав, але не зміг знайти. Дякую.
ДАВС

6
Вибачте і якщо я хочу перетворити це зображення у файл, не отримуючи реального шляху, як це зробити?
Хлебта

6
Фізичний шлях надає доступ до назви файла та розширення. У разі завантаження файлів.
Clocker

195

Це те, що я роблю:

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

і:

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

ПРИМІТКА: managedQuery()метод застарілий, тому я його не використовую.

Остання редакція: Покращення. Ми повинні закрити курсор !!


1
stackoverflow.com/a/7265235/375093 Це ще один варіант, але пропонується як кращий, ніж вище. Перевірте і це
Sundeep

6
Привіт @ m3n0R, у Moto G, MediaStore.Images.ImageColumns.DATA стовпець взагалі не існує. Як отримати зображення без цього стовпця?
набряки

16
ПОМИЛКА Переконайтесь, що курсор ініціалізований правильно перед тим, як отримати доступ до даних. Перевірка в API 19
Mayur R. Amipara

1
@ReneJuuse: Відмінний ресурс. Зрештою, мені вдалося вирішити цю проблему завдяки цьому - я не розумів, що з моменту створення Android було так багато змін. Я запускав API 21, і коли я використовував реалізацію API 19, показану на веб-сайті, на якому ви зв’язувались, він нарешті спрацював.
Мілош Іванович

2
Не вдалося прочитати рядок 0, стовпчик -1 від CursorWindow. Переконайтесь, що курсор ініціалізований правильно, перш ніж отримувати доступ до даних з нього.
Maveň ツ

18

@Rene Juuse - вище в коментарях ... Дякую за це посилання!

. код для отримання реального шляху трохи відрізняється від одного SDK до іншого, тому нижче ми маємо три методи, що стосуються різних SDK.

getRealPathFromURI_API19 (): повертає реальний шлях для API 19 (або вище, але не перевіряється) getRealPathFromURI_API11to18 (): повертає реальний шлях для API 11 до API 18 getRealPathFromURI_below11 (): повертає реальний шлях для API нижче 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);
}

шрифт: http://hmkcode.com/android-display-selected-image-and-its-real-path/


ОНОВЛЕННЯ 2016 березня

Щоб виправити всі проблеми із зображенням шляху, я спробую створити власну галерею як facebook та інші додатки. Це тому, що ви можете використовувати лише локальні файли (справжні файли, а не віртуальні чи тимчасові), і я вирішую всі проблеми з цією бібліотекою.

https://github.com/nohana/Laevatein (ця бібліотека - робити фотографії з камери або вибирати з галереї; якщо ви вибираєте з галереї, у нього є ящик з альбомами та просто показувати локальні файли)


@Clocker на Samsung S4 також
Рікардо

Мені справді важко керувати всіма типами вихідних зображень в Android. Якщо ви завантажуєте або приймаєте вибір із галереї, найкращим рішенням буде створення галереї з facebook. Це власна галерея із просто реальними зображеннями в пристрої, без віртуальних чи тимчасових. Я вирішую всі проблеми в моєму додатку за допомогою цієї бібліотеки. github.com/nohana/Laevatein Справді гарна бібліотека. Налаштувати не просто, але ви можете відкрити код і внести свої зміни. Я сподіваюся, що це може вам допомогти.
luizfelipetx

Поламаний на моєму Samsung S2 з 4.4.1
Олівер Діксон

Мені потрібно отримати такі файли, як pdf чи doc, я не можу отримати шлях. Чи можете ви мені допомогти?
Аніш Кумар

1
Дивовижно! Нарешті щось, що справді працює. Шукав цього довго. Дякую.
Джаватар

14

Примітка. Це вдосконалення у відповіді @ user3516549, і я перевірив це на Moto G3 з Android 6.0.1.
У мене це питання, тому я спробував відповісти на @ user3516549, але в деяких випадках він не працює належним чином. Я виявив, що в Android 6.0 (або вище), коли ми починаємо наміри вибору зображень галереї, тоді відкриється екран, на якому відображаються останні зображення, коли користувач вибирає зображення зі цього списку, ми отримуємо uri як

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

тоді як якщо користувач вибере галерею з розсувного ящика замість останнього, то ми отримаємо uri як

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

Отже, я впораюся з цим 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: якщо ви намагаєтеся отримати шлях зображення до зовнішньої sdcard у вищій версії, тоді перевірте моє запитання


Привіт друже, так це правда. але це відбувається тому, що тепер Google має стандартний формат для завантаження всіх фотографій з телефону в документи Google. І просто збережіть ескіз у телефоні. Якщо ви отримуєте цей урі з google docs, вам потрібно завантажити його, перш ніж використовувати його. Це взагалі не добре. Отже, щоб виправити всі проблеми тут, тепер я використовую цю бібліотеку. (ця бібліотека просто використовує локальні файли, і з цим рішенням ваші проблеми будуть вирішені), або ви можете витягнути код з бібліотеки та вдосконалити себе для участі у своїй проблемі. github.com/nohana/Laevatein Я сподіваюся, що це може вам допомогти.
luizfelipetx

1+, Його робота ідеально підходить для мене. Як заявив @JaiprakasSoni у своїй відповіді, що я зіткнувся з тією ж проблемою, коли я запускаю свою програму в грі Moto G4, але коли я використовую вищезгаданий код, це працює добре для мене. Дякую тобі. Ви економите мій час
Шайлеш

6

РЕДАКТУЙ: Використовуйте це рішення тут: https://stackoverflow.com/a/20559175/2033223 Працює ідеально!

Перш за все, дякую за ваше рішення @luizfelipetx

Я трохи змінив ваше рішення. Це працює для мене:

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

Примітка. Отже, ми отримали документи та зображення, залежно від того, якщо зображення надходить із "вступників", "галереї" чи будь-коли. Тому я витягую ідентифікатор зображення спочатку, перш ніж його шукати.


1

Привіт, ось мій повний код для зйомки зображення з камери чи галереї

// Моя змінна декларація

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

// Onclick

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

// метод методу

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

// І решта речей

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

Як ви знаєте, 100 в цьому рядку options.inSampleSize = calculateInSampleSize(options, 100, 100);
Джон Джо

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.