Avoiding Running Out Of Memory
I???ve implemented a simple picture picker widget in this Android app I???m
working on. Here???s the guts of the code that initializes it:
ThePics.Clear();
final String ExternalStorage =
android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
final String[] Places =
{
ExternalStorage.concat("/Pictures"),
ExternalStorage.concat("/DCIM"),
};
for (String Place : Places)
{
final java.io.File ThisDir = new java.io.File(Place);
if (ThisDir.isDirectory())
{
for (java.io.File Item : ThisDir.listFiles())
{
android.graphics.Bitmap ThisImage =
android.graphics.BitmapFactory.decodeFile(Item.getAbsolutePath());
if (ThisImage != null)
{
ThePics.AppendItem(ThisImage, Item, Item.getName());
} /*if*/
} /*for*/
} /*if*/
} /*for*/
ThePics.notifyDataSetChanged();
The first time after the app was launched, bringing up the picker would
work. But on the second time, the app would crash with
???java.lang.OutOfMemoryError: bitmap size exceeds VM budget??? in
android.graphics.BitmapFactory.decodeFile.
Even rotating the phone (which causes the re-creation of the activity)
triggered the crash.
Just to make it clear, the widget does NOT keep a reference to the Bitmap
that is passed; it creates a copy, scaled as necessary so as not to exceed a
maximum thumbnail size (160x160 pixels). So each thumbnail should take no
more than about 100K max, and my phone only has about a dozen pictures on
it.
I went over the ???Avoiding Memory Leaks??? article
<http://developer.android.com/resources/articles/avoiding-memory-leaks.html>,
looking carefully for unwanted references that might be preventing bitmaps
from being freed.
Finally, one simple change did the trick: after that ThePics.Append call
above, I added
ThisImage.recycle();
and that fixed it! Now I can bring up the picker multiple times during a
single app invocation, rotate the phone any number of times I like, and it
all works nicely.
So the question is: why was the garbage collector being so tardy in
reclaiming all those loaded full-size images?