android uri.getPath() and performance - android

I am thinking about using uri.getPath().
But I am a bit confused because of a code snippet that I have seen online, shown below. In the example the author tries to retrieve the image in a different way first.
So I am wondering whether there are some serious performance disadvantages using uri.getPath()? (Or why does he not simply skip the media store part?)
/**
* helper to retrieve the path of an image URI
*/
public String getPath(Uri uri) {
// just some safety built in
if( uri == null ) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
// this is our fallback here
return uri.getPath();
}
from https://stackoverflow.com/a/21018617/3991799

Related

Is there a reliable way to get the MediaStore asset from a image picker URL

When using the default photo picker, one only receives an URL to the image or video.
I would like to also get some Media Store metadata, but am not sure if there is a way to get the media store asset from the url.
How would I get it?
Seems like this could be a reliable solution:
String[] projection = {MediaStore.Images.Media._ID};
String selection = MediaStore.Images.Media.DATA + " = ?";
String[] selectionArgs = {imageURL};
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
long id = cursor.getLong(idColumn);
// Do something with the image ID.
}
if (cursor != null) {
cursor.close();
}

Error getting image path selected by Gallery Intent (Android 6 - Some devices)

I am trying to get the path of an image when the user pick from the gallery (with intent)
It's been working ok, since some users noticed that could not do it witn Android 6.0.
I have tried different things, and some solutions works in the emulator with Android 6.0 but not in my Xiamoi with Android 6.1.
This both solutions works in the emulator (6.0) and Android 4.4 physycal device.
public String getRealPathFromURI(Activity context, Uri contentURI) {
String[] projection = { MediaStore.Images.Media.DATA };
#SuppressWarnings("deprecation")
Cursor cursor = context.managedQuery(contentURI, projection, null,
null, null);
if (cursor == null)
return null;
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
String s = cursor.getString(column_index);
// cursor.close();
return s;
}
// cursor.close();
return null;
}
and the other similar:
private static String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
But in my Xiaomi 6.1 the cursor is null. But I can get the real path from:
private static String getRealPathFromURI(Context context, Uri contentUri) {
return contentUri.getEncodedPath();
}
Any help?
Thank you!
EDIT:
I'm asking for choose an image in this way:
Intent intent = new Intent();
// Show only images, no videos or anything else
intent.setType("image/*");
intent.setAction(Intent.ACTION_PICK); //ACTION_GET_CONTENT
// Always show the chooser (if there are multiple options available)
launchForResult(Intent.createChooser(intent, "Select Picture"), SELECT_FILE);
I'm asking for choose an image in this way:
First, use ACTION_GET_CONTENT to pick by MIME type.
Second, whatever activity that responds to ACTION_GET_CONTENT (or ACTION_PICK) does not need to return a Uri that the MediaStore knows about. In fact, most will not. They can return a Uri that points to anything, including things that are not files.
So, get rid of all of your broken getRealPathFromURI() code. Use ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri, and use that stream.

How to get last image captured with camera in android? [duplicate]

This question already has answers here:
get the last picture taken by user
(3 answers)
Closed 9 years ago.
My intention is not to take a picture and then save it to sd card , get the link and all. The image is already taked with the original camera app in the android.
All i need it how can i get that image path with respect to sd card like
emulated/0/sdcard/DCIM/100ANDRO/image.jpg
how do i get that format of the recently taken image.
I've accomplished it like this:
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID + " DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
imageCursor.moveToFirst();
do {
String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
if (fullPath.contains("DCIM")) {
//--last image from camera --
return;
}
}
while (imageCursor.moveToNext());
Use this to get path of file from URI:
Uri selectedImageUri = data.getData();
selectedImagePath = getRealPathFromURI(selectedImageUri);
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
Cursor provides random read-write access to the result set returned by a database query.
getContentResolver () returns a ContentResolver instance for your application's package.
When you want to access data in a content provider, you use the ContentResolver object in your application's Context to communicate with the provider as a client. The ContentResolver object communicates with the provider object, an instance of a class that implements ContentProvider. The provider object receives data requests from clients, performs the requested action, and returns the results.
The Content Resolver includes the CRUD (create, read, update, delete) methods corresponding to the abstract methods (insert, delete, query, update) in the Content Provider class. The Content Resolver does not know the implementation of the Content Providers it is interacting with (nor does it need to know); each method is passed an URI that specifies the Content Provider to interact with.
MediaStore: The Media provider contains meta data for all available media on both internal and external storage devices. MediaStore.images contains meta data for all available images.

Android - MediaStore.Video.query() is returning null

I'm trying to retrieve the metadata from a video file (title, language, artist) using the method MediaStore.Video.query(). However, the method is always returning null. The code is bellow:
String[] columns = {
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.TITLE,
MediaStore.Video.VideoColumns.ARTIST
};
Cursor cursor = MediaStore.Video.query(getApplicationContext().getContentResolver(), videoUri,columns);
if (cursor != null) {
cursor.moveToNext();
}
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE));
Any suggestion about how to return video metadata using android?
==Update
As I searched in many places, I tried one solution using CursorLoader. However, the method loadInBackground() from CursorLoader is also returning null. The code is showed bellow:
String[] columns = {
MediaStore.Video.VideoColumns.TITLE
};
Uri videoUri = Uri.parse("content://mnt/sdcard/Movies/landscapes.mp4");
CursorLoader loader = new CursorLoader(getBaseContext(), videoUri, columns, null, null, null);
Cursor cursor = loader.loadInBackground();
cursor.moveToFirst();
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE));
Uri.parse("content://mnt/sdcard/Movies/landscapes.mp4") is not an Uri for MediaStore. It would try to find a ContentProvider for authority mnt which does not exist.
MediaStore can handle only content://media/... Uris which you should get exclusively via MediaStore, not by using Uri.parse().
In your case use the following for example
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] columns = {
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.TITLE,
MediaStore.Video.VideoColumns.ARTIST
};
String selection = MediaStore.Video.VideoColumns.DATA + "=?";
String selectionArgs[] = { "/mnt/sdcard/Movies/landscapes.mp4" };
Cursor cursor = context.getContentResolver().query(uri, columns, selection, selectionArgs, null);
The MediaStore.Video.VideoColumns.DATA field holds the path to the videos and you search for a certain video this way. At least for now, future versions of Android may change that.
Your second example is using CursorLoader the wrong way. If you call loader.loadInBackground() yourself, you load the data in foreground. See e.g. http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/
The next thing you do is
Cursor cursor = getCursor();
cursor.moveToFirst();
String title = cursor.getString(/* some index */);
This will lead to a CursorIndexOutOfBoundsException if your cursor has 0 rows and cursor.moveToFirst() failed because there is no first row. The cursor stays before the first row (at -1) and that index does not exist. That would mean in your case that the file was not found in the database.
To prevent that use the return value of moveToFirst - it will only be true if there is a first row.
Cursor cursor = getCursor(); // from somewhere
if (cursor.moveToFirst()) {
String title = cursor.getString(/* some index */);
}
A more complete example including checks for null and closing the cursor in all cases
Cursor cursor = getCursor(); // from somewhere
String title = "not found";
if (cursor != null) {
if (cursor.moveToFirst()) {
title = cursor.getString(/* some index */);
}
cursor.close();
}
I guess the file you try to find is either not indexed in the database (rebooting forces the indexer to run again) or the path is wrong.
Or the path you use is actually a symlink in which case MediaStore might use a different path.
Use this to get rid of symlinks
String path = "/mnt/sdcard/Movies/landscapes.mp4";
try {
path = new File(path).getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
}
Yes, I tested now and it is throwing IndexOutOfBoundsException. When I'm using cursor.getColumnCount() it returns 1
cursor.getColumnCount() is the column count, not the row count. It should always be the same as the number of columns you requested in columns. You need to check cursor.getCount() if you want to check the row count.
Try dumping all the videos known to MediaStore into logcat in case it does not show as expected.
public static void dumpVideos(Context context) {
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
vidsCount = c.getCount();
while (c.moveToNext()) {
Log.d("VIDEO", c.getString(0));
}
c.close();
}
Log.d("VIDEO", "Total count of videos: " + vidsCount);
}
I updated your code, it works, just check it
public static void dumpVideos(Context context) {
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
c.moveToFirst();
vidsCount = c.getCount();
do {
Log.d("VIDEO", c.getString(0));
}while (c.moveToNext());
c.close();
}
Log.d("VIDEO", "Total count of videos: " + vidsCount);
}

How to query Android MediaStore Content Provider, avoiding orphaned images?

I'm trying to provide an in-app Activity which displays thumbnails of photos in the
device's media store, and allow the user to select one. After the user makes a
selection, the application reads the original full-size image and does things with it.
I'm using the following code to create a Cursor over all the images on the external
storage:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView( R.layout.image_select );
mGridView = (GridView) findViewById( R.id.image_select_grid );
// Query for all images on external storage
String[] projection = { MediaStore.Images.Media._ID };
String selection = "";
String [] selectionArgs = null;
mImageCursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
// Initialize an adapter to display images in grid
if ( mImageCursor != null ) {
mImageCursor.moveToFirst();
mAdapter = new LazyCursorAdapter(this, mImageCursor, R.drawable.image_select_default);
mGridView.setAdapter( mAdapter );
} else {
Log.i(TAG, "System media store is empty.");
}
}
And the following code to load the thumbnail image (Android 2.x code is shown):
// ...
// Build URI to the main image from the cursor
int imageID = cursor.getInt( cursor.getColumnIndex(MediaStore.Images.Media._ID) );
Uri uri = Uri.withAppendedPath( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
Integer.toString(imageID) );
loadThumbnailImage( uri.toString() );
// ...
protected Bitmap loadThumbnailImage( String url ) {
// Get original image ID
int originalImageId = Integer.parseInt(url.substring(url.lastIndexOf("/") + 1, url.length()));
// Get (or create upon demand) the micro thumbnail for the original image.
return MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(),
originalImageId, MediaStore.Images.Thumbnails.MICRO_KIND, null);
}
And the following code to load the original image from the URL once the user makes a selection:
public Bitmap loadFullImage( Context context, Uri photoUri ) {
Cursor photoCursor = null;
try {
// Attempt to fetch asset filename for image
String[] projection = { MediaStore.Images.Media.DATA };
photoCursor = context.getContentResolver().query( photoUri,
projection, null, null, null );
if ( photoCursor != null && photoCursor.getCount() == 1 ) {
photoCursor.moveToFirst();
String photoFilePath = photoCursor.getString(
photoCursor.getColumnIndex(MediaStore.Images.Media.DATA) );
// Load image from path
return BitmapFactory.decodeFile( photoFilePath, null );
}
} finally {
if ( photoCursor != null ) {
photoCursor.close();
}
}
return null;
}
The problem I'm seeing on some Android devices, including my own personal phone, is that the
cursor I get from the query in onCreate() contains a few entries for which the actual full-sized image file (JPG or PNG) is missing. (In the case of my phone, the images had been imported and subsequently erased by iPhoto).
The orphaned entries may or may not have thumbnails, depending upon whether thumbnails where generated before the actual media file when AWOL. The end result is that the app displays thumbnails for images that don't actually exist.
I have a few questions:
Is there a query I can make to the MediaStore content provider that will filter out
images with missing media in the returned Cursor?
Is there a means, or an API to force the MediaStore to rescan, and eliminate the orphan entries? On my phone, I USB-mounted then unmounted the external media, which is supposed to trigger a rescan. But the orphan entries remain.
Or is there something fundamentally wrong with my approach that's causing this problem?
Thanks.
Okay, I've found the problem with this code sample.
In the onCreate() method, I had this line:
mImageCursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
The problem here is that it's querying for the thumbnails, rather than the actual images. The camera app on HTC devices does not create thumbnails by default, and so this query will fail to return images that do not already have thumbnails calculated.
Instead, query for the actual images themselves:
mImageCursor = managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
This will return a cursor containing all the full-sized images on the system. You can then call:
Bitmap bm = MediaStore.Images.Thumbnails.getThumbnail(context.getContentResolver(),
imageId, MediaStore.Images.Thumbnails.MINI_KIND, null);
which will return the medium-sized thumbnail for the associated full-size image, generating it if necessary. To get the micro-sized thumbnail, just use MediaStore.Images.Thumbnails.MICRO_KIND instead.
This also solved the problem of finding thumbnails that have dangling references to the original full-sized images.
Please note that things will be changing soon, managedQuery method is deprecated. Use CursorLoader instead(since api level 11).

Categories

Resources