Compat libraries incompatibilities
Compat libraries are great. They allow us to work with the newest Android APIs, without thinking (much) about your minimum API level. Instead of thousands of devices, you can reach billions. With nearly no changes in your code.
But sometimes, they’re not so great…
Support for vector drawables (mainly SVGs files) has been added in API 21. They come in two kinds: still and animated. They’re great for many reasons: they scale properly, you don’t have to keep multiple densities of the same image anymore, you can reference colors and dimensions from resources, you can do path morphing… well, almost.
In order to use vector drawables on pre-21 APIs, Google released a set of two
support libraries, com.android.support:vector-drawable
and
com.android.support:animated-vector-drawable
. The first one works starting
with API 7, the latest with API 11. Everything is explained
here.
Still drawables should work exactly the same regarding the API level you’re running. On the animated version, however, there’s a catch: you can’t animate all the properties you can on 21+. From the documentation:
Note that the animation in AnimatedVectorDrawableCompat has to be valid and functional based on the SDK version the app will be running on. Before SDK version 21, the animation system didn’t support the following features:
- Path Morphing (PathType evaluator). This is used for morphing one path into another.
- Path Interpolation. This is used to define a flexible interpolator (represented as a path) instead of the system defined ones like LinearInterpolator.
- Animating 2 values in one ObjectAnimator according to one path’s X value and Y value. One usage is moving one object in both X and Y dimensions along a path.
Let’s say you want an animation using path morphing. Place your vector drawable
in the drawable-v21
folder and add a fallback with a rotation or whatever in
the drawable
one, and you’re good to go, right? Right?
The same page of the documentation also mentions this:
For API 24 and above, this class is delegating to the framework’s AnimatedVectorDrawable. For older API version, this class uses ObjectAnimator and AnimatorSet to animate the properties of a VectorDrawableCompat to create an animated drawable.
And here come troubles. The reasoning behind this is that SDK’s implementation
on APIs 21 to 23 contains some bugs.
However, using an AnimatedVectorDrawableCompat
on an API 21 device comes with
the same limitations as running on an API 19 device: you’re using the SDK’s
ObjectAnimator
and AnimatorSet
, and they do not know the support libraries
symbols. More specifically, they don’t know how to animate any
android.support.graphics.drawable.PathParser$PathDataNode
(what they do know
about is the android.util.PathParser$PathDataNode
class).
If you’re looking for more technical bits, I wrote some more notes on this StackOverflow question as I stumbled upon this issue.
As a result, on APIs 21 to 23, any path-morphing animation fails silently when using the support libraries. There’s a work-around, though. You can use the SDK’s implementation to load your vector drawable:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Casting the drawable to an AnimatedVectorDrawable is useless here
// It's just to show that you don't get an AnimatedVectorDrawableCompat
AnimatedVectorDrawable drawable = (AnimatedVectorDrawable) getDrawable(R.drawable.ic_animated_drawable_32dp);
mBinding.imageView.setImageDrawable(drawable);
} else {
mBinding.imageView.setImageResource(R.drawable.ic_animated_drawable_32dp);
}
// Starting the animation works whatever the implementation we're using now
final Drawable animation = mBinding.imageView.getDrawable();
if (animation instanceof Animatable) {
((Animatable) animation).start();
}
However, using the SDK’s implementation obviously means not making use of the support library’s bug-fixes. It will probably work for simple drawables, but may fail on more complex ones.
As a final note: if you’re using animated vector drawables, remember to test not only on whatever your minimum SDK is and your latest shiny device, but also on APIs 21 to 23. You might be surprised.