Android получить реальный путь Uri.getPath()

Я пытаюсь получить изображение из галереи.

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

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

Ответ 2

Это то, что я делаю:

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() метод устарел, поэтому я его не использую.

Последнее редактирование: Улучшение. Мы должны закрыть курсор!

Ответ 3

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

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


ОБНОВЛЕНИЕ 2016 Март

Чтобы устранить все проблемы с образами изображений, я попытаюсь создать собственную галерею как facebook и другие приложения. Это связано с тем, что вы можете использовать только локальные файлы (реальные файлы, а не виртуальные или временные), я решаю все проблемы с этой библиотекой.

https://github.com/nohana/Laevatein (эта библиотека должна делать фото с камеры или выбирать из галереи, если вы выберете из галереи, у него есть ящик с альбомами и просто показывать локальные файлы)

Ответ 4

Примечание Это улучшение в @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-карте в более высокой версии, а затем проверьте мой вопрос

Ответ 5

EDIT: Используйте это решение здесь: fooobar.com/questions/12193/... Прекрасно работает!

Во-первых, спасибо за ваше решение @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;
}

Примечание. Таким образом, мы получили документы и изображения, в зависимости, если изображение происходит от "recents", "gallery" или того, что когда-либо было. Поэтому сначала я извлекаю идентификатор изображения, прежде чем искать его.

Ответ 6

Как знают фактические программисты, нет реального пути.

A Uri с схемой content - непрозрачный дескриптор некоторого содержимого. Если этот Uri представляет открываемый контент, вы можете использовать ContentResolver и openInputStream(), чтобы получить InputStream в этом контенте. Аналогично, a Uri с схемой http или https не представляет собой локальный файл, и вам нужно будет использовать API-интерфейс HTTP для доступа к нему.

Только Uri с схемой file идентифицирует файл (запрет на случай, когда файл был перемещен или удален после создания Uri).

Какие глупые люди пытаются получить путь к файловой системе, пытаясь декодировать содержимое Uri, возможно, в сочетании с заклинаниями заклинания для вызова $EVIL_DEITY. В лучшем случае это будет ненадежным по трем причинам:

  • Правила для декодирования значений Uri могут меняться со временем, например, с версиями версий для Android, поскольку структура Uri представляет деталь реализации, а не интерфейс

  • Даже если вы получите путь к файловой системе, у вас могут не быть прав на доступ к файлу

  • Не все значения Uri могут быть декодированы с помощью фиксированных алгоритмов, так как у многих приложений есть свои собственные поставщики, и они могут указывать на все: от активов до столбцов BLOB до данных, которые необходимо передавать из Интернета

Ни один разработчик с каким-либо здравым смыслом не идет по этому пути.

Если у вас есть ограниченный API, для которого требуется файл, используйте InputStream from openInputStream(), чтобы сделать копию этого содержимого. Независимо от того, является ли это временной копией (например, используется для операции загрузки файла, затем удаляется) или долговечной копией (например, для функции "импорта" вашего приложения) зависит от вас.

Ответ 7

Hii вот мой полный код для взятия изображения с камеры или galeery

//Объявление переменной

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