我有一个onActivityResult从一个mediastore图像选择返回,我可以获得一个图像使用以下URI:

Uri selectedImage = data.getData();

将this转换为字符串会得到:

content://media/external/images/media/47

或路径给出:

/external/images/media/47

然而,我似乎找不到一种方法将其转换为绝对路径,因为我想将图像加载到位图中,而不必复制到某个地方。我知道这可以使用URI和内容解析器来完成,但这似乎在重新启动手机时中断,我猜MediaStore在重新启动之间没有保持其编号相同。


当前回答

像下面这样获取Uri。

//* get cursor like normal

Then

while (cursor.moveToNext()) {
    Uri uri = ContentUris.withAppendedId(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
}

其他回答

在这里,我将向您展示如何创建一个BROWSE按钮,当您单击它时,它将打开SD卡,您将选择一个文件,结果您将获得所选文件的文件名和文件路径:

一个你要按的按钮

browse.setOnClickListener(new OnClickListener()
{
    public void onClick(View v)
    {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_PICK);
        Uri startDir = Uri.fromFile(new File("/sdcard"));
        startActivityForResult(intent, PICK_REQUEST_CODE);
    }
});

获取结果文件名和文件路径的函数

protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
    if (requestCode == PICK_REQUEST_CODE)
    {
        if (resultCode == RESULT_OK)
        {
            Uri uri = intent.getData();

            if (uri.getScheme().toString().compareTo("content")==0)
            {
                Cursor cursor =getContentResolver().query(uri, null, null, null, null);
                if (cursor.moveToFirst())
                {
                    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
                    Uri filePathUri = Uri.parse(cursor.getString(column_index));
                    String file_name = filePathUri.getLastPathSegment().toString();
                    String file_path=filePathUri.getPath();
                    Toast.makeText(this,"File Name & PATH are:"+file_name+"\n"+file_path, Toast.LENGTH_LONG).show();
                }
            }
        }
    }
}

这些答案在所有情况下都不适用。我必须直接去谷歌的文档https://developer.android.com/guide/topics/providers/document-provider.html关于这个主题,并发现这个有用的方法:

private Bitmap getBitmapFromUri(Uri uri) throws IOException {
    ParcelFileDescriptor parcelFileDescriptor =
    getContentResolver().openFileDescriptor(uri, "r");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    parcelFileDescriptor.close();
    return image;
}

您可以使用此位图在图像视图中显示它。

既然上面的答案对我不起作用,下面是对我有效的解决方案:

对于>19和<=19 API级别。

这个方法涵盖了从uri中获取filePath的所有情况

/**
 * Get a file path from a Uri. This will get the the path for Storage Access
 * Framework Documents, as well as the _data field for the MediaStore and
 * other file-based ContentProviders.
 *
 * @param context The activity.
 * @param uri The Uri to query.
 * @author paulburke
 */
public static String getPath(final Context context, final Uri uri) {

    // DocumentProvider
    if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }else{
                Toast.makeText(context, "Could not get file path. Please try again", Toast.LENGTH_SHORT).show();
            }
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            } else {
                contentUri = MediaStore.Files.getContentUri("external");
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

现有的很好的答案,其中一些是我自己想出来的:

我必须从URI中获取路径,并从路径中获取URI,谷歌很难区分,因此对于任何有相同问题的人(例如,从MediaStore中获取视频的缩略图,其物理位置您已经拥有)。前:

/**
 * Gets the corresponding path to a file from the given content:// URI
 * @param selectedVideoUri The content:// URI to find the file path from
 * @param contentResolver The content resolver to use to perform the query.
 * @return the file path as a string
 */
private String getFilePathFromContentUri(Uri selectedVideoUri,
        ContentResolver contentResolver) {
    String filePath;
    String[] filePathColumn = {MediaColumns.DATA};

    Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}

后者(我用于视频,但也可以用于音频或文件或其他类型的存储内容,通过替换MediaStore。音频(等)MediaStore.Video):

/**
 * Gets the MediaStore video ID of a given file on external storage
 * @param filePath The path (on external storage) of the file to resolve the ID of
 * @param contentResolver The content resolver to use to perform the query.
 * @return the video ID as a long
 */
private long getVideoIdFromFilePath(String filePath,
        ContentResolver contentResolver) {


    long videoId;
    Log.d(TAG,"Loading file " + filePath);

            // This returns us content://media/external/videos/media (or something like that)
            // I pass in "external" because that's the MediaStore's name for the external
            // storage on my device (the other possibility is "internal")
    Uri videosUri = MediaStore.Video.Media.getContentUri("external");

    Log.d(TAG,"videosUri = " + videosUri.toString());

    String[] projection = {MediaStore.Video.VideoColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(projection[0]);
    videoId = cursor.getLong(columnIndex);

    Log.d(TAG,"Video ID is " + videoId);
    cursor.close();
    return videoId;
}

基本上,MediaStore的DATA列(或正在查询的任何子部分)存储文件路径,因此您可以使用已知的内容查找DATA字段,也可以使用该字段查找所需的任何其他内容。

然后,我进一步使用上述方案来确定如何处理我的数据:

 private boolean  getSelectedVideo(Intent imageReturnedIntent, boolean fromData) {

    Uri selectedVideoUri;

    //Selected image returned from another activity
            // A parameter I pass myself to know whether or not I'm being "shared via" or
            // whether I'm working internally to my app (fromData = working internally)
    if(fromData){
        selectedVideoUri = imageReturnedIntent.getData();
    } else {
        //Selected image returned from SEND intent 
                    // which I register to receive in my manifest
                    // (so people can "share via" my app)
        selectedVideoUri = (Uri)getIntent().getExtras().get(Intent.EXTRA_STREAM);
    }

    Log.d(TAG,"SelectedVideoUri = " + selectedVideoUri);

    String filePath;

    String scheme = selectedVideoUri.getScheme(); 
    ContentResolver contentResolver = getContentResolver();
    long videoId;

    // If we are sent file://something or content://org.openintents.filemanager/mimetype/something...
    if(scheme.equals("file") || (scheme.equals("content") && selectedVideoUri.getEncodedAuthority().equals("org.openintents.filemanager"))){

        // Get the path
        filePath = selectedVideoUri.getPath();

        // Trim the path if necessary
        // openintents filemanager returns content://org.openintents.filemanager/mimetype//mnt/sdcard/xxxx.mp4
        if(filePath.startsWith("/mimetype/")){
            String trimmedFilePath = filePath.substring("/mimetype/".length());
            filePath = trimmedFilePath.substring(trimmedFilePath.indexOf("/"));
        }

        // Get the video ID from the path
        videoId = getVideoIdFromFilePath(filePath, contentResolver);

    } else if(scheme.equals("content")){

        // If we are given another content:// URI, look it up in the media provider
        videoId = Long.valueOf(selectedVideoUri.getLastPathSegment());
        filePath = getFilePathFromContentUri(selectedVideoUri, contentResolver);

    } else {
        Log.d(TAG,"Failed to load URI " + selectedVideoUri.toString());
        return false;
    }

     return true;
 }

如果你的系统版本在19以上,这对我来说是完美的,希望这能帮助你。

  @TargetApi(Build.VERSION_CODES.KITKAT)
    public static String getPath(final Context context, final Uri uri) {
        final boolean isOverKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        // DocumentProvider
        if (isOverKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/"
                            + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(id));
                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }
                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};
                return getDataColumn(context, contentUri, selection,
                        selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
        return null;
    }