3

I am reading an image from disk and displaying it inside of a row in a ListView. The image files are larger than what needs to be displayed inside the ImageView of the rows. Since I need to cache the bitmaps in RAM for faster access I would like them to only be as large as the ImageViews (85x85 dip)

Right now I am reading in the file with

bitmap = BitmapFactory.decodeFile(file);

and the ImageView is responsible for scaling and cropping it

android:scaleType="centerCrop"

AFAIK this is keeping the entire bitmap in memory (because I cached it XD) and that is bad

How can I remove this responsibility from the ImageView and do the crop + scale while loading the file? All the bitmaps will be displayed at 85x85 dip and need to be 'centerCrop'

smith324
  • 13,020
  • 9
  • 37
  • 58

1 Answers1

6

You can find out the dimensions of your pictures before loading, cropping and scaling:


BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    Bitmap bmo = BitmapFactory.decodeFile(file.getAbsolutePath(), options);

Then load it in sample size:


...
options.inSampleSize = 1/2;
bmo = BitmapFactory.decodeFile(file.getAbsolutePath(), options);

...
 = Bitmap.createScaledBitmap(bmo, dW, dH, false);

don't forget to recycle temporary bitmaps or you'll get OOME.


bmo.recycle();
Phyrum Tea
  • 2,623
  • 1
  • 19
  • 20
  • 2
    I was trying to avoid aggressively allocating and deallocating memory like this. Also your `inSampleSize` is not doing anything in this sample. It needs to be set > 1 to do anything, preferably in powers of 2. http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize And for my cropping, I would still like to do it myself than letting the `ImageView` do it, otherwise I'm wasting memory. – smith324 Jan 03 '11 at 00:39
  • If you have an own ListAdapter, you can set the Bitmap of the view in getView – Phyrum Tea Jan 03 '11 at 11:52
  • @Phyrum Tea well I haven't found any information about doing a crop manually so I guess I'm forced to let `ImageView` handle that. If I'm going to be doing that, then I can use getHeight() and getWidth() on the first bitmap to calculate the correct way to scale the bitmap. – smith324 Jan 03 '11 at 18:49
  • @Phyrum Tea one more question, why do you set `inJustDecodeBounds` ?from what I've read it allocates memory but not the actual bitmap. Why is this useful? Is it quicker to call or something? – smith324 Jan 03 '11 at 18:51
  • It just reads the picture to find out it's dimension, so we can decide what sample size to use to get our picture. If you have in ImageView not the final picture, maybe a simpler default one, with the right size. It won't have to scale. If you inflate the listrow from XML you could process your final image yourself. – Phyrum Tea Jan 05 '11 at 12:25
  • Maybe I was wrongly assuming that you have your own ListAdapter. My example depends on that assumption. – Phyrum Tea Jan 05 '11 at 12:27
  • @Phyrum Tea The way my custom `BaseAdapter` works is that all the `ImageViews` must be (by design choice) the same exact size when displayed on screen, hence the whole cropping thing. For example if a picture is in portrait I need to crop it rather than scale it (making it stretch oddly) so that all my pictures are perfect squares. Currently `centerCrop` does that so I'll keep that part of my implementation as is. – smith324 Jan 06 '11 at 05:27