Video as an Animation Method on Android

Matt Carron
Oct 21, 2019 · 7 min read

There are a number of different animation methods available for you as an Android developer. Connie Reinholdsson and I delivered a talk about this at Code Mobile 2019. We are following that talk up with a series of blog posts to dive into more detail on these methods.

Video may not come to mind when you think Android animation, however there are certain situations where video has to be used or is better suited to the media.

In this article we will talk through how we built AutoSergei at comparethemarket.com and the reason we decided to use video in this case. Let’s get started!

The source video we need to animate

Image for post
Image for post
One of the AutoSergei animations in the Meerkat App

Animation sections:
Lets start by breaking the animation down into sections:

  • Fur moving
  • Eye opening and closing
  • Head rotating
  • Tie blinking

Due to the complexity of this asset we ruled out using the Android Framework’s animation framework directly via `ViewAnimations` or `PropertyAnimators` but we did look into the Android Drawable animations and Vector Drawable Animations as possibilities.

Instead of animating views or properties, we can create an animation by providing a set of Drawables to be frames within an animation each with a duration to be visible for.

This approach is quite expensive from a APK size point of view due to the large number of frames required for our asset. The source video is about 4.5 seconds long and with it’s frame rate of 25 frames a second that is around 112 individual drawables to create the Android Drawable Animation. One compressed PNG frame is about 131kb at the source resolution, 112 frames would be about 17mb! Or even compressed JPEG was 51kb or 6.9mb! As the source video was less at 1.8mb, going up in APK size was not something I wanted.

AnimatedVectorDrawables lets you create drawables you can scale without loss of quality. From the Android docs:

It lets you animate the properties of a vector drawable, such as rotating it or changing the path data to morph it into a different image.

This tool is very powerful leveraging vector drawables however frankly I was unsure how we could use vector assets to recreate the asset. 🤷‍♂️

Another solution we looked into was using a GIF and even GIFs of just the parts that move overlaid onto an image, to reduce the size of the final asset.

We currently use Picasso in the Meerkat app which does not support animated GIFs. However Glide, another image loading library does alongside having a very similar API to Picasso making a possible move simpler.

A GIF created at the same resolution is 2.4mb this was greater than the original 1.8mb video file. This was better then the other options so far however still not better then just using the video itself.

Maybe we should just use video?

Videos allow for very rich and complex content that can come straight from designers and be used by both Android and iOS however it’s not without it’s challenges.

So after reviewing a handful of alternatives I’m staring back at the original asset and wondering if we can just use video.

Lets go through my concerns and see how we can combat them and how they sometimes compare to our previous alternatives.

So the biggest issue we were trying to avoid was the file size hit to the APK however we saw that alternatives to using video actually had larger hits to APK size.

Now the video asset straight from the designers was 1.8mb, this is pretty small for a video however as mobile developers we need to be aware: larger the app becomes the slower it will be to download from the store. Additionally even if the user downloaded the app it will take up more storage on their device. This was a big concern for us as just one video asset can be in megabytes.

Lets see if we can get a better size via compression.

Image for post
Image for post
HandBrake, a free and open-source transcoder for digital video files 👍

Above I have kept the majority of the video settings the same (resolution, video codex and framerate) what I have changed is the quality.

The quality is controlled by the big slider, for x264 video it’s recommended to stay between 28 and 18 (lower the number higher the quality, 0 is lossless)

After starting at 28 and comparing with the source video you could see the quality difference, mostly in the detail like the hair. So working back until it became difficult to see the quality loss, we ended up landing on 25

Image for post
Image for post
Compressed and original asset side by side

Original is 1.8mb and the compressed 182kb, almost a 10x saving in APK size! 🎉

Which one do you think is which? …. 🥁 The right image is the compressed video! 🔥

This saving is not completely free, this compression is not lossless, if you look very closely there is slightly less definition. The level of compression and the visual affect it brings is going to be different depending on what you have in the video and what your business’s requirements are and what quality they are willing to accept.

So file size is no longer an issue however what about compatibility?

You may have noticed there were some settings in the Handbrake compression screenshot that I did not explain.

Image for post
Image for post

One of these settings was the encoding options and more specifically the profile option. Depending on which is selected will limit which Android versions will be able to play decode and play it. In the android docs they list the video codex support.

Image for post
Image for post
  • Android 3+ supports video encoded with H.264 on the AVC Baseline Profile (BP)
  • Android 6+ supports video encoded with H.264 on the AVC Main Profile (MP)

Baseline supports a much larger number of devices so why would you not just go for Baseline all the time? Well it will create a larger video file then the Main Profile. In our example it was the difference between 182kb with Main Profile and 240kb with Baseline, that is a 30% increase in file size if you use the Baseline profile.

However even by using the Baseline profile we are still ending up with a much smaller APK size than other approaches or just the original asset.

Additionally instead of relying on the varying video player shipped the many different makes and flavours of Android. We chose to add Google’s ExoPlayer to our application giving us a consistent playback experience.

There are two types of jank I think and worry about with video.

  • Loading time
    When playing a video on Android it has to load it into memory before it can render the first frame, due to this it normally result in a noticeable blink or flash at the start of the video.
  • Juddering during playback
    This is a device performance issue when the device cannot render the frames of the video fast enough to keep up with the intended frame rate. This can happen on older devices that are not powerful enough to handle sensibly sized assets this is hopefully a very small percentage of your user base. The second is self inflicted, if you include a video with a very high resolution that is not suitable for the devices of your user base at the time.

We can help mitigate the juddering during playback by choosing a sensible resolution for our user base which we could do via looking at our analytics.

However the loading time is noticeable even with a sensible resolution, so to help smooth out this effect we can set the first frame as a loading state for the video until it’s loaded.

Below is a test of this loading state. In both tests the video is loaded onCreate of the activity.
The left test is without any loading image, the right has a loading image. You can see that Android can load up the image asset much faster and helps the the video merge into the rest of the UI more seamlessly.

Image for post
Image for post
Left without loading image <-> Right with loading image

I have put together a small custom view that wraps up this loading image behaviour for easy use. Here is how it’s used from code, we pass the resource ID of the first frame that we exported from the video and the video itself and that is it.

The custom view then handles the switching from loading image to video. The ExoPlayer library allows for setting a handy callback for when the first frame of the source video has rendered, this is perfect for the effect we are after.

You will find the example code pictured above at the following Github repo mattcarron/animation-samples

In this article we have explored why we settled on video as an animation method, what the issues are with using it and ways so help mitigate these issues. Leaving us with a great animation tool to have on our belt.

Thank you for reading, it would be great to hear your feedback! ✌️

Image for post
Image for post

Compare the Market

The people behind comparethemarket.com and the Meerkat App

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store