Android dev tip: Replace PNG assets with XML drawables

tl;dr: You’ll save a lot of memory.

The best way to fix OutOfMemoryException problems in Android is never to have them, so it’s important to be proactive about limiting the amount of memory that your app uses.  Sometimes this means bossing around your designers.  Let me explain why with a story…

button

Your designer hands you a design with a PNG that looks like this (well, hopefully your designer hands you things that look nicer than this, since I have no idea what I’m doing, but let’s ignore that for a minute, shall we?  K thx.)

It’s just a little thing, just 300×100 dp.  So you lay out the screen, run the app and everything is hunky-dory, until you look at the Memory Monitor in Android Studio and notice your app’s memory usage just jumped by about 1 MB.

png-mem-jump

What the hell just happened?

That’s no good.  Surely adding a simple button can’t cost a megabyte of memory.

finder-smallYou look at the PNG you just added, but it’s only 10 KB.  That can’t be the problem, can it?  Turns out, it is.  What you’re looking at in Finder is the compressed image file, but Android doesn’t keep the file compressed when it loads.  It renders your PNG to a Bitmap, which is the most un-compressed way to store an image.  It’s just a big matrix of pixels with a color value for each pixel.  By default, Android uses the ARGB_8888 format which uses 4 bytes per pixel.  And oh yeah, we’re looking at an XXHDPI device, so our 300dp width is actually 900 pixels.  That means our “little” 900×300 pixel image is using 1,080,000 bytes (1.03 MB) for its Bitmap.  

mem-dump-byte-array

Yeah, that really sucks.

So are you stuck with the sad fact that you’re now 1 MB closer to exploding your app by running out of memory?  Do you DM your designer on Slack and tell them they’re a bad person and they’re killing the app?  (Pro-tip: don’t ever do that)

There’s a better way.  You can draw the same thing to the screen using an XML Drawable and a Button.

Now let’s check that memory usage again.

xml-tiny-jumpOur XML-based drawable is using 504 bytes in memory.  Oh that’s nice.

Moral of the Story

Now obviously this won’t work for every asset; once you get past basic shapes, you’ll still need assets for anything complex.  But by being vigilant, and replacing simple assets with XML drawables, you delay the time when you’ll face the inevitable OutOfMemoryException.

4865622