So far, we have solved Cursor == null when retrieved via ContentResolver by using separate logic for SDKs <11, 11-18, >=19. Something like
public static Cursor getRealPathFromURI_API19(Context context, Uri uri) {
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);
return cursor;
}
public static Cursor getRealPathFromURI_API11to18(Context context, Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
String result = null;
CursorLoader cursorLoader = new CursorLoader(context, contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
return cursor;
}
public static Cursor getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
return cursor;
}
However, on Galaxy S5, when we save an image to its own directory in the internal public memory (not private data/data), we get cursor==null. On other devices, we DON't get null cursor.
The flow of the app is like this:
Take image with Camera
Save it into file in its own directory (public directory in internal memory)
Access file via ContentResolver and return Cursor
Steps 1 and 2 are properly done. Verified! I can see the image I take via Camera inside the specified directory.
I also checked if the Bitmap is accessible via
InputStream input;
Bitmap bmp;
try {
input = getContentResolver().openInputStream(uri);
bmp = BitmapFactory.decodeStream(input);
} catch (FileNotFoundException e1) {
Log.e("tafg", "error");
}
and I never get an exception.
However, in spite of all this, Cursor remains null on some devices. Anyone can guess why and what is the ultimate way never to get null cursor?
PS. is there any 3rd party library that handles this part properly?
PPS. We are using Retrofit to get up to 10 images saved via Camera and upload to the remote server. Using and working with Bitmap is not possible in this case as we get OOM on the 5th or 6th image. So Retrofit logic must use ContentResolver to get hold of the image(s) that need(s) to be uploaded.
So far, we have solved Cursor == null when retrieved via ContentResolver by using separate logic for SDKs <11, 11-18, >=19.
I strongly recommend that you delete all that code and use a Uri properly.
The flow of the app is like this:
Your step #3 is pointless. You know where the file is, because you put it there in step #2. And, by getting rid of step #3, you can also get rid of all of the bogus "real path" code.
Anyone can guess why
Perhaps MediaStore does not know about the image, because it has not been indexed yet. See MediaScannerConnection and its scanFile() method.
Also note that you are not actually setting cursor to a value in getRealPathFromURI_API19(). I would expect that code to not compile, so I am assuming that it is a copy/paste problem in your question.
what is the ultimate way never to get null cursor?
Stop querying for it in the first place.
Related
I have image uri like this :"content://com.iceburgapp.provider/external_files/.pkgName/File1.jpg"
Now whenever I get path it give me : "/external_files/.pkgName/File1.jpg"
I want to get RealPathFrom content Uri.
I got solution from stackoverflow and I tried below code but not working for me :
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();
}
}
}
AnyOne know How to do this? I got below error for using above code.
java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: []
It's only not working in the Nought and oreo device because of contentUri using file provider.
Use a ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri. Ideally, just use that stream directly, for whatever it is that you are trying to do. Or, use that InputStream and some FileOutputStream on a file that you control to make a copy of the content, then use that file.
This is working properly in devices before Android N
I'm trying to show thumbnails of images from sdcard in a gridview. I'm using universal image loader and image loading is takes reasonable time.
My problem is: trying to get all paths for the thumbnails takes too much time and causes lag on the gridview scroll. If i try ro read all paths ahead of the loading images then it takes 10 seconds (500 images on S5). I see a lot of app already solved this problem and it seems i am making some fundemantal mistakes here, yet i couldn't find what it is.
PS: I got this code from an answer on stackoverflow and i think my problem is not related to code but it is related with my approach to the problem.
Here is the code:
public static String getThumbnailPath(Activity activity, long imageId) {
String[] proj = { MediaStore.Images.Media.DATA };
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
CursorLoader cursorLoader = new CursorLoader(activity, uri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
cursor.moveToFirst();
String result="";
cursor = MediaStore.Images.Thumbnails.queryMiniThumbnail(activity.getContentResolver(), imageId,
MediaStore.Images.Thumbnails.MINI_KIND, null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails.DATA));
cursor.close();
}
result = "file://" + result;
return result;
}
Have a look at smoothie by Lucas Rocha. It is a library project for fast scrolling listviews and gridviews. I use it in my app Playlist Manager. Easy to implement.
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.
Gah, another scenario here something that should be simple is proving to be very time-consuming and painful.
I'm using this to query the contacts provider:
private Cursor getContacts(){
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_ID
};
......
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
}
This works fine and retrieves contact names, and on a handful of contacts it shows a numeric ID for the PHOTO_ID field, which I assume is the PHOTO_ID I'm requesting. But then I push that ID into this method to extract the bitmap, it fails on every contact and the stream is null every time. I'm testing against a set of contacts that includes some with Android contact photos (I know there are some issues extracting photos from Facebook contacts).
private Bitmap loadContactPhoto(long id) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, uri);
if (input == null) return null;
Bitmap bitmap = BitmapFactory.decodeStream(input);
return bitmap;
}
What have I missed?
openContactPhotoInputStream() takes the uri of the contact, try calling it with the ContactsContract.Contacts._ID column instead of the PHOTO_ID column and you should see better results.
There's a bunch of relevant discussion here with some code to check out:
How do I load a contact Photo?
Note that in some cases you'll see a photo in the native contacts app which won't load through the content resolver. Some sync info, like Facebook for example, is flagged to be used only by the contacts app itself and doesn't get exported to other apps :-(
However, using the contactUri should take care of at least some of your issues.
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).