Search code examples
androidandroid-contentresolver

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 the 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.
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!


Solution

  • 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 (e.g., from the InputStream) to a file that you control (e.g., in getCacheDir()).

    As a bonus, now your code is also in position to use the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT) and the Internet (e.g., OkHttp), if and when that would be useful.