简体   繁体   中英

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. 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 theDATA attribute everyone's using is deprecated . In the official docs, they recommend to use FileDescriptor instead, problem is i don't know exactly how.
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) .

Even tried retrieving a file from Google Drive - and it worked. Only problem was the long time it took (about 20 sec for 5MB file).

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.

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

@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.

That code may not work for all images. There is no requirement for DATA to point to a filesystem path that you can access.

Just like this answer.

FWIW, this was my answer to that question.

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 .

In the official docs, they recommend to use FileDescriptor instead, problem is i don't know exactly how.

The more general concept is that you use ContentResolver to work with the Uri , whether you get an InputStream ( openInputStream() ), OutputStream ( openOutputStream() ), or 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() ).

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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