Get real path from Uri - DATA is deprecated in android Q
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 (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.