Difference between .getPath() vs cursor in getting the real path of a file from uri in Android
The main idea of the question is just same as the title - what is the difference between .getPath() vs cursor, when you get the real path of a file from uri in Android?
In case you don't get what I meant by using cursor, the example is here.
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;
}
The two most frequent ways were these two, but it seems a bit too complicated using cursor, while you can get the same result with one simple method, .getPath(). So, I think there must be the reason I should use the cursor in some cases, but I can't get it.
Could you explain me what it would be?
Solution 1:
what is the difference between .getPath() vs cursor, when you get the real path of a file from uri in Android?
A Uri
is not a file. There is no "real path".
If the scheme of the Uri
is file
, then it represents a file on the filesystem that, in theory, your app should be able to access. Use getPath()
to get the filesystem path.
If the scheme is anything else, it does not necessarily represent a file on the filesystem that your app can access. For example, if the scheme is http
or https
, the Uri
represents something that would be downloaded from a Web server.
If the scheme is content
, then it is backed by a ContentProvider
. Use a ContentResolver
and openInputStream()
to get an InputStream
on the content identified by the Uri
.
If the scheme is content
and you specifically obtained the Uri
from the MediaStore
, then perhaps your Cursor
approach will give you a path. It also might give you null
, and the path that you get may not be accessible to you (just because the system's MediaStore
can index a file does not imply that your app has access to that same file). This is worse on Android 10, where you do not have read access to external storage by default. Hence, this technique is unreliable and should not be used.
Beyond that, though, you cannot make any assumptions about what data is used to support that content
Uri
. It could be:
- A local file on external storage
- A local file on internal storage for the other app (e.g., served by
FileProvider
) - A local file on removable storage
- A local file that is encrypted and needs to be decrypted on the fly by the
ContentProvider
- A stream of bytes held in a
BLOB
column in a database that needs to be served by theContentProvider
- A piece of content that needs to be downloaded by the other app first (e.g., Dropbox)
- ...and so on
So, to recap: a Uri
is not a file. There is no "real path".