This is part three of the bitmaps mini-series of posts.
If you skipped part 1 and 2, that’s okay for this post, but it will help you have a much stronger understanding of why the code works how it works if you do read parts 1 and 2. For this post, I’ll be sharing some code I’ve used across Xamarin Android projects that helps with cleaning up android bitmaps.
Shared
For methods I’ll be using across entire apps, I like to put them in a static class called Shared, where all methods and members are static. This enables easy use of general purpose methods across all activities, classes, etc. Just for anyone who doesn’t know, static classes in C# only have one instance, and they cannot be instantiated, members and methods are invoked by simply using the class name. This also means that static classes are garbage collector roots that never get cleaned up, meaning however big that class is on the heap, that class occupies that much memory for the entirety of the lifecycle of the app. Anyways, let’s move on.
Generic sweeping across runtimes
First and foremost, you’re going to need a method to do major collections across both runtimes, you don’t technically have to do this, but if you need memory freed right then and there, you do. For this, I create a generic method called Sweep (sorry about the dots, wordpress sucks at formatting code):
....public static void Sweep()
....{
........GC.Collect();
........Java.Lang.JavaSystem.Gc();
....}
So as you can see, this is pretty simple, calling Sweep simply invokes both runtimes garbage collectors.
Cleaning bitmaps
Cleaning bitmaps takes a little bit more code, but not too much, to clean a bitmap I use the following code:
....public static void CleanBitmap(Bitmap bitmap, bool sweep = true)
....{
........if (!bitmap.IsRecycled)
........{
............bitmap.Recycle();
............bitmap.Dispose();
............bitmap = null;
........}
........if (sweep)
........{
............Sweep();
........}
....}
This method takes a bitmap to be cleaned, and a boolean sweep. Since major collections are expensive and take a long time to do, I like to be able to specify when I’d like a sweep to occur, so if I have say 10 bitmaps that need cleaned, I can pass false and manually call sweep, or I can pass true and the sweep will occur as a part of the bitmap cleanup. Besides that, this method checks if the bitmap has been recycled to avoid accidentally trying to recycle a recycled bitmap which would case a crash, and if it hasn’t been recycled, it recycles, disposes, and nulls out the bitmap, which frees the bitmap memory, disposes the mono handle, and nulls out the bitmap to break the cyclic reference between the two runtimes.
Cleaning image view bitmaps
The final method I use for cleaning bitmaps allows me to easily clean up bitmaps that are tied to an image view, the code is as follows:
....public static void CleanImageViewBitmap(ImageView imageView, bool sweep = true)
....{
........Drawable drawable = imageView.Drawable;
........if (drawable is BitmapDrawable)
........{
............BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
............if (bitmapDrawable.Bitmap != null)
............{
................Bitmap bitmap = bitmapDrawable.Bitmap;
................if (!bitmap.IsRecycled)
................{
....................imageView.SetImageBitmap(null);
....................imageView.Dispose();
....................bitmap.Recycle();
....................bitmap.Dispose();
....................bitmap = null;
................}
............}
........}
........if (sweep)
........{
............Sweep();
........}
....}
Pretty similar to the CleanBitmap method from before, except in this case we pass an image view, get it’s bitmap drawable, make sure it’s not null and hasn’t been recycled, and we set the image view bitmap to null, dispose the image view, and repeat for the bitmap itself. This will ensure that the entirety of the image view gets cleaned up. Just like before, we can optionally decide if we want a sweep to occur or not.
In terms of bitmap cleanup, that’s all there really is to it, everything else you may need to do should just be variations of this code. In the next post, we’ll look at optimizing loading bitmaps to reduce memory overhead, which is the other big part of the equation. Thanks for reading, and if you have any question, comments, or concerns with anything I said, feel free to leave a comment or email me.