I notice a different behavior in android management of thumbnails.
This is my code:
String[] sProjection = new String[]{MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.DISPLAY_NAME,MediaStore.Images.Media.DATA,
MediaStore.Images.Media._ID};
Cursor oCur = oActivity.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
sProjection,"",null,MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
do{
...
Bitmap oBmp = MediaStore.Images.Thumbnails.getThumbnail(oActivity.getContentResolver(),bmpID,
MediaStore.Images.Thumbnails.MICRO_KIND,null);
...
}while (oCur.moveToNext());
And then after loading all thumbnails, I make some elaborations with some of them.
With my mobile (Android 4.1.2) after loading all thumbnails for the first time (for example with new photos or after cleaning cache in Media Storage), "do while" loop is very quick because all the tumbanails are already created and saved in cache.
With another one (same Android version) every time you execute the loop there are no improvements of velocity, because it doesn't save them but it recalculate them all (viewed with the messages in Eclipse LogCat).
Why do this happen?! Is there a way to solve this issue and to force Android save thumbnails in cache memory?
Thanks a lot for the help, any suggestion is greatly appreciated.
Related
So I am displaying video files from specific folder when the folder is selected but in the video list I am showing file name with the video thumbnail and that's where the problem starts i am using this way to get the thumb
Bitmap bmThumbnail = ThumbnailUtils.
extractThumbnail(ThumbnailUtils.createVideoThumbnail(info.getFilename(),
MediaStore.Video.Thumbnails.MINI_KIND), 60, 60);
if(bmThumbnail != null) {
imageView.setImageBitmap(bmThumbnail);}
and even if I don't set the bitmap or not the process is taking way too much time to open the new fragment whereas just displaying the name is smooth if I call the following bitmap it takes around 6-7 sec to display the list. The following thing are happening in the adapter as I test the app in adapter then recycler view
so I would like to know what is the best way to do it .
For using image loader i need the url which is not there as i am getting the album art using the file url but it will not produce the album art url directly.
Dealing with images and videos like that takes time. Particularly when dealing with a large group of them. It's unlikely you can speed up the operation but you can make it so your application doesn't have to wait for it by sending it to the background. I recommend Kotlin coroutines if you are up for converting to Kotlin. Otherwise I recommend making a thumbnail work manager
public class VideoThumbnailWorker extends Worker {
}
For my app, I'm currently reading through ALL the image (JPEG) files stored on the phone and saving their ID, and thumbnails (NOT the original Bitmap) onto a HashMap.
Code:
final String[] PROJECTION =
new String[] {MediaStore.Images.Media._ID};
Cursor pictureCursor = getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI,
PROJECTION, null, null, MediaStore.Images.Media._ID);
HashMap<Integer,Bitmap> thumbnails = new HashMap<Integer,Bitmap>();
int id;
int id_index = pictureCursor.getColumnIndex(MediaStore.Images.Media._ID);
int THUMBNAIL_TYPE = MediaStore.Images.Thumbnails.MICRO_KIND;
ContentResolver content_resolver = context.getContentResolver();
while (pictureCursor.moveToNext()) {
id = pictureCursor.getInt(id_index);
Bitmap thumbnail = MediaStore.Images.Thumbnails.getThumbnail(content_resolver, id, THUMBNAIL_TYPE, null);
thumbnails.put(id, thumbnail);
}
I currently have 200 images on my phone, and it works fine now. But I'm worried that at certain point, the app will run out of memory and crash.
Is running out of memory something I need to take into consideration? Or are thumbnails small enough that practically speaking, the app won't run out of memory?
EDIT
If I should worry about running out of memory, what's the best way if I want something like Android's native gallery app, which doesn't seem to have a "load more images" button but rather an endless stream of images?
Thanks
MICRO_KIND thumbnails are not very big, and you will very likely be fine. But if you are putting your app out there, you will absolutely find people with memory problems. It will be due to either an insane number of photos, a mediocre device, or some combination of the two.
You can calculate the memory use of your thumbnails. It shouldn't be too hard to create one or two thumbnails, and find out how big they are. Then you can calculate available heap (Native heap on pre 3.0, Dalvik heap after 3.0) and get an idea of how many you can make.
You can get a count of the items in your cursor at this point in your code:
Cursor pictureCursor = getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI,
PROJECTION, null, null, MediaStore.Images.Media._ID);
int numberOfImages = pictureCursor.getCount()
HashMap thumbnails = new HashMap();
and then know if you have plenty of room or not. If you are limited in space, you will need to make a design decision--either warn the user that its not going to work, or only look at the first "x" images, then free those up and load another set at the users request.
It depends on heap size and how memory intensive your app is.
I suggest you have a look at the video in the link
http://www.youtube.com/watch?v=_CruQY55HOk.
If you run into memory leaks you can use MAT Analyzer to find and fix the problem.
You need to reduce memory usage and if heap sizes grows and your app requires space in heap, the gc kicks in to free memory. But if there is not enough space you are likely to run into memory leaks.
http://developer.android.com/training/articles/perf-tips.html
I'm trying to implement a gallery and I have a GridView that displays all the images (thumbnail) in the camera folder. To get the thumbnails, I basically get their IDs using:
final String[] PROJECTION =
new String[] {MediaStore.Images.Media._ID};
Cursor pictureCursor = getActivity().getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI,
PROJECTION, null, null, MediaStore.Images.Media._ID);
ArrayList<Integer> ids = new ArrayList<Integer>();
int idIndex = pictureCursor.getColumnIndex(MediaStore.Images.Media._ID);
while (pictureCursor.moveToNext()) {
ids.add(pictureCursor.getInt(idIndex));
}
And to read the thumbnails, I'm using
Bitmap bitmap = MediaStore.Images.Thumbnails.getThumbnail(content_resolver, ids.get(position), MediaStore.Images.Thumbnails.MICRO_KIND, null);
on an AsyncTask as specified in http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
But as I'm comparing the load times between my app vs. Android's native gallery app, I'm seeing that the gallery app loads thumbnails MUCH faster than my app, all the while having better image quality than my Thumbnails.MICRO_KIND. Is there a faster way to load thumbnails than to use MediaStore.Images.Thumbnails.getThumbnail() function? because obviously the gallery app loads thumbnails much faster.
NOTE: this is when the app is initially opened, before cache comes into play. After my cache stores images, then load time is near instant. So, not a cache problem.
EDIT:
I thought I should clarify. It's not that my UI is getting locked or my app is slow, since I'm already using an AsyncTask to read my images off the UI thread. What I'm asking is if the function MediaStore.Images.Thumbnails.getThumbnail() is the fastest way to load thumbnails already stored on the phone?
Use Universal Image Loader it takes care of your issues which most likely stems from you loading the wrong sizes and/or not caching the results.
I am downloading images from server into the ListView and storing it into SD Card.
And when next time listview appears i am accessing it from SD card only using Async method, i
use this approch so that every thing user does not need to access server.
But when all the images are being loaded into listview from SD Card and if i scroll it
pretty fast then every time it tries to access it from the SD Card only rather then from Caches i guess.
I was facing the same problem when images are being downloaded from server also , and thats why i thought to store it into SD Card. but i am facing the same issue.
here is my code ListImageDownloader . In that there is a function called downloadBitmap(String) and i have created another function named downloadSDBitmap(String) whose code is as follows
Bitmap downloadSDBitmap(String urlId) {
Bitmap bitmap = null;
File file = new File(
fileLoc +"/"+ urlId+".png");
if(file.exists()){
Log.d("PATH" , file.getAbsolutePath());
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
}
return bitmap;
}
apart from this the whole caching code and all are same. so can anyone help me how can i improve it as in a Gtalk android application when i scroll fast it loads the images only once after that if i scroll fast the images remains as it is and doesnt fetch from network
Update
these are my parameters
final static int MAX_ENTRIES = 150;
private static final int HARD_CACHE_CAPACITY =50;
private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds
Caching fundamentally relies on available memory. If there is memory left for your application you will need to implement a good solution that caches your bitmaps.
In the past was SoftReference/WeakReference a popular method to cache bitmaps (I did try it a year ago, you can read about my question about this here). But in later APIs of Android the garbage collector has become more aggressive collecting those and therefore they are not no longer recommended.
Now it is recommended to use an LRU cache. There is an example available on the Android developers website.
I guess this question has been asked before, but I can't seem to find a proper answer/solution.
Have a note-taking app, which allows to take pictures. For that I start an intent, that starts up the built-in camera-app. So far so good.
But when I show that image in my app, it's in a much smaller format :(
The funny/weird thing is, that the camera-app did take a full-resolution picture! But for some reason I can't get the full version to show in my app???
So, when I use the standard Android Gallery app, and go to that picture, it is very obvious that it's full size (I can zoom in and see details I really can't see when I zoom in, in my own app). Also, the dimensions are really those of the original picture, taken with the 5MP camera.
In my app, they are very small. My phone has Android 2.2, but the same happens on my emulator (Android 2.1).
How should I retrieve the pictures in my app??? Tried a couple of ways, but none works :( Don't need a complete example (allthough that's very welcome), just a few clues are enough to search for myself.
Tx in advance!!
Greetingz,
Koen<
Very weird, I found the solution/answer by looking at the _ID-values that were being inserted in my own database. First I noticed that when I selected an existing image (via the build-in Android Gallery), I did get the full size image.
When I first took a picture, I got a scaled image. So where was the difference. Apparantly at the location where the _ID of the picture got stored in my database. In my case, and probably most cases, this happens in the onActivityResult procedure.
First take a look at what I initially had:
if(requestCode == REQUEST_CAMERA && resultCode == RESULT_OK){
String timestamp = Long.toString(System.currentTimeMillis());
// get the picture
mPicture = (Bitmap)result.getExtras().get("data");
//save image to gallery
String pictureUrl = MediaStore.Images.Media.insertImage(getContentResolver(), mPicture, getResources().getString(R.string.app_name_short), timestamp);
insertPictureAttachment(mRowId.intValue(), Integer.parseInt(Uri.parse(pictureUrl).getLastPathSegment()));
The "insertPictureAttachment"-method does the actual inserting into the database.
Looking backwards, this was a bit weird anyway ... make a picture, so I could make an URI of it, and then get the last path segment (which is the _ID), so I could insert that into my database.
Eventually, it turns out that I can replace the above code with just one line:
insertPictureAttachment(mRowId.intValue(), Integer.parseInt(result.getData().getLastPathSegment()));
Much shorter, and actually makes more sense ... rather than getting the info from result.getExtras().get("data"), I get my info from result.getData(), which gives the _ID of the original, full-size image.
I will do some further research on this though, cause it's not clear to me yet why I actually don't have to call MediaStore.Images.Media.insertImage(...) ... maybe I will have to if I want specific features (like a custom file location or something like that).
Greetingz,
Koen<