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()не даст вам реальный путь?
Darpan
#Try This Все же, если у вас возникла проблема, чтобы найти реальный путь, вы можете попробовать мои ответы. Приведенные выше ответы мне не помогли. Объяснение : - Этот метод получает URI, а затем проверяет уровень API вашего устройства Android, после чего в соответствии с уровнем API он сгенерирует реальный путь. Код для генерации реального пути различается в зависимости от уровня API. Вот мой ответ
Сунил

Ответы:

56

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

Молнарм
источник
Это именно то, что я искал, но не смог найти. Спасибо.
Дэвс
6
Извините, и если я хочу преобразовать это изображение в файл, не получив реального пути, как это сделать?
Chlebta
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 вообще нет. Как получить изображение без этой колонки?
seema
16
ОШИБКА. Убедитесь, что Курсор правильно инициализирован, прежде чем получить доступ к данным из него .. проверка в API 19
Маюр Р. Амипара
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
Потрясающие! Наконец то, что действительно работает. Искал это очень давно. Спасибо.
Javatar
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)
        }

    }

РЕДАКТИРОВАТЬ: если вы пытаетесь получить путь к файлу изображения на внешней SD-карте в более поздней версии, проверьте мой вопрос

Джайпракаш Сони
источник
Привет, друг, да, это правда. но это происходит потому, что теперь у Google есть формат по умолчанию для загрузки всех фотографий с вашего телефона в документы Google. И просто сохраните миниатюру в свой телефон. Если вы получили этот URI из документов Google, вам необходимо загрузить фотографию, прежде чем использовать ее. В целом это нехорошо. Итак, чтобы исправить все проблемы здесь, я использую эту библиотеку. (эта библиотека просто использует локальные файлы, и с этим решением ваши проблемы будут решены), или вы можете извлечь код из библиотеки и улучшить себя, чтобы решить вашу проблему. 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;

//По щелчку

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);
Джон Джо