简体   繁体   English

从 Uri 获取真实路径 - DATA 在 android Q 中已弃用

[英]Get real path from Uri - DATA is deprecated in android Q

I'm successfully implementing a method for retrieving the real path of an image from gallery by the Uri returned from ACTION_PICK intent.我正在成功实现一种方法,该方法通过从ACTION_PICK意图返回的Uri从图库中检索图像的真实路径。 Here's a sample:这是一个示例:

// getRealPathFromURI(intent.getData());

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

Just like this answer .就像这个答案一样。

Recently updated the compileSdkVersion to 29 and apparently the最近将compileSdkVersion更新为29 ,显然DATA attribute everyone's using is deprecated .每个人都使用的属性已弃用 In the official docs, they recommend to use FileDescriptor instead, problem is i don't know exactly how.在官方文档中,他们建议改用FileDescriptor ,问题是我不知道具体如何。
Only thing i found is this question .我唯一发现的是这个问题 Didn't find a proper answer there though.虽然没有找到正确的答案。

Please help me overcome that deprecation issue with a solution using the suggested way or any other way.请使用建议的方式或任何其他方式帮助我解决该弃用问题。

Thank you.谢谢你。


Update:更新:

Followed @CommonsWare 's answer and copied the returned Uri (of an image the user picked) to a local directory, using context.getContentResolver.openInputStream(Uri) .遵循@CommonsWare回答并使用context.getContentResolver.openInputStream(Uri)将返回的 Uri(用户选择的图像)复制到本地目录。

Even tried retrieving a file from Google Drive - and it worked.甚至尝试从 Google Drive 中检索文件 - 并且成功了。 Only problem was the long time it took (about 20 sec for 5MB file).唯一的问题是花费了很长时间(5MB 文件大约需要 20 秒)。

As a bonus, i was cleared to remove external storage permissions, which one doesn't need for using app's local directories.作为奖励,我被清除删除外部存储权限,使用应用程序的本地目录不需要该权限。

No more externals paths for me!我没有更多的外部路径!

This question came up for me too a week ago.一周前我也提出了这个问题。

My solution was to create an InputStream from the URI and then, from this, create an OutputStream by copying the contents of the input stream.我的解决方案是从 URI 创建一个InputStream ,然后通过复制输入流的内容来创建一个OutputStream

Note: You could call this method using an asynchronous call because copying extremely large files could have some delays and you won't want to block your UI注意:您可以使用异步调用来调用此方法,因为复制非常大的文件可能会有一些延迟,并且您不想阻塞您的 UI

@Nullable
public static String createCopyAndReturnRealPath(
       @NonNull Context context, @NonNull Uri uri) {
    final ContentResolver contentResolver = context.getContentResolver();
    if (contentResolver == null)
        return null;

    // Create file path inside app's data dir
    String filePath = context.getApplicationInfo().dataDir + File.separator
            + System.currentTimeMillis();

    File file = new File(filePath);
    try {
        InputStream inputStream = contentResolver.openInputStream(uri);
        if (inputStream == null)
            return null;

        OutputStream outputStream = new FileOutputStream(file);
        byte[] buf = new byte[1024];
        int len;
        while ((len = inputStream.read(buf)) > 0)
            outputStream.write(buf, 0, len);

        outputStream.close();
        inputStream.close();
    } catch (IOException ignore) {
        return null;
    }

    return file.getAbsolutePath();
}

I'm successfully implementing a method for retrieving the real path of an image from gallery by the Uri returned from ACTION_PICK intent.我正在成功实现一种方法,该方法通过从 ACTION_PICK 意图返回的 Uri 从图库中检索图像的真实路径。

That code may not work for all images.该代码可能不适用于所有图像。 There is no requirement for DATA to point to a filesystem path that you can access. DATA不需要指向您可以访问的文件系统路径。

Just like this answer.就像这个答案一样。

FWIW, this was my answer to that question. FWIW,是我对那个问题的回答。

Only thing i found is this question.我发现的唯一一件事就是这个问题。 Didn't find a proper answer there though.虽然没有找到正确的答案。

That technique wasn't particularly good and will no longer work, as Android has locked down /proc .由于 Android 已锁定/proc ,因此该技术不是特别好并且将不再起作用。

In the official docs, they recommend to use FileDescriptor instead, problem is i don't know exactly how.在官方文档中,他们建议改用 FileDescriptor,问题是我不知道具体如何。

The more general concept is that you use ContentResolver to work with the Uri , whether you get an InputStream ( openInputStream() ), OutputStream ( openOutputStream() ), or FileDescriptor .更一般的概念是您使用ContentResolver来处理Uri ,无论您获得InputStream ( openInputStream() )、 OutputStream ( openOutputStream() ) 还是FileDescriptor Consume the content using those things.使用这些东西来消费内容。 If you have some API that absolutely needs a file, copy the content (eg, from the InputStream ) to a file that you control (eg, in getCacheDir() ).如果您有一些绝对需要文件的 API,请将内容(例如,从InputStream中)复制到您控制的文件中(例如,在getCacheDir()中)。

As a bonus, now your code is also in position to use the Storage Access Framework (eg, ACTION_OPEN_DOCUMENT ) and the Internet (eg, OkHttp), if and when that would be useful.作为奖励,现在您的代码也可以使用存储访问框架(例如ACTION_OPEN_DOCUMENT )和 Internet(例如 OkHttp),如果它们有用的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM