[MUSIC PLAYING]
Compressed image formats like PNG, JPEG, and WebP
do a fantastic job of reducing the file size of your images
for distribution and transfer.
But once the images get off the disk and into memory,
all those great compression savings disappear.
My name is Colt McAnlis, and serious application developers
know that smaller images don't have to stop with disk formats.
With the help of some of Android's built in features,
you can reduce the amount of heap space
that your images are taking up, which
can improve memory efficiency and performance.
It's worth pointing out that the Dalvik version of Android's
garbage collector is non-compacting,
meaning that as objects are freed,
other objects will not be shuffled around in order
to optimize for free space.
This represents a large problem for bitmaps,
which tend to be the largest continuous blocks of memory
that you'll actually allocate in your app.
The less contiguous free space there is in your heap
means that allocations for bitmaps
can fail, causing a garbage collection
event to be kicked off in order to free up
space in other places so that the allocation can eventually
succeed or throw an out of memory error.
The reason that these images are so large in memory
is that before you can use JPEG or PNG files,
they first have to be loaded into memory
and decompressed to a format that the system can
use for rendering, meaning that once they're loaded,
they aren't in their compressed form anymore.
Nope, they're sitting around on your CPU memory
in all of their uncompressed glory.
And by default, when images are loaded
into a bitmap in Android, they're
done so at 32 bits per pixel, giving eight bits
to each of the red, green, blue, and alpha channels.
This happens even if you're loading an image without alpha,
like a JPEG image.
Currently, Android doesn't have support
for 24 bits per pixel image formats,
meaning that even if your image doesn't use alpha,
when it's loaded, it'll get converted to a 32-bit format
in memory, basically weighting eight bits per pixel.
Oh, and don't forget that before these images can be rendered
to the screen, they first have to be transferred to the GPU
as textures, which means that each bitmap you create
is going to be taking up CPU memory and GPU
memory at the same time.
In order to address these problems,
Android supports a few alternate pixel formats
that when used properly can provide smaller
CPU and GPU footprints, leading to less heap fragmentation
and better performance.
Of course, the trick here is that the savings of the space
comes at the cost of visual quality, which
means that these formats may not be
right for every single scenario.
For example, utilizing the RGB565 format
allows you to use only 16 bits per pixel
and ignore allocating any bits to the alpha channel.
Of course, you've now cut the amount of information per pixel
in half, which reduces the number
of possible unique colors in your image.
This is most noticeable in gradient areas of your images
or in icons, but for most photos,
the difference is really hard to notice, especially
on a very tiny screen.
Now, if you want smaller format but you still need alpha,
trying the 4444 image format, which basically
cuts the number of bits per pixel in half
and keeps the alpha channel, but of course
introduces larger visual differences.
This lower quality means that you're
going to end up with significant banding in areas
of the image that have smooth gradients.
So it's not really appropriate for full screen high resolution
photos, but it can easily work as a format for thumbnails that
might need some alpha applied to them,
like if you're baking in rounded corners to your images
or something like that.
Now, while Android doesn't support gray scale bitmaps,
the Alpha8 format can still be quite used for alpha masking.
For instance, creating a simple grey icon and then using
a color tint at run time to turn it into the color that you
actually want on the screen.
You'll get a little extra overhead
during the rendering of your image,
but this might be a huge win with respect
to memory resonancy.
Now, it's worth pointing out that PNG, JPEG, and WebP don't
support these smaller pixel formats as part
of their basic file structure, meaning that at load time,
you're going to have to set the inPreferredConfig
flag of your bitmap options to whatever the target pixel
format is that you're looking to use.
When the image is loaded, the system will go load the data,
convert it to the format on your behalf.
Just be aware though that when it does this,
you may get some extra processing
time as a result, which is really important to note.
Performance is all about trade offs.
Image memory size, visual quality, and load times,
it's all things that you have to balance perfectly
for your application to get the best performance possible.
Of course, that's why you need to check out the rest
of the Android performance patterns content and also join
our Google+ community for great tips on other developers on how
they balanced this tricky equation.
So keep calm, profile your code, and always remember,
perfmatters.