Deal with vector drawable on Android 5.0 and older versions

Anthony Stéphan
3 min readOct 1, 2018

--

Vector drawable are probably the best addition to the Android SDK for the last years

Today (most of the time), you don’t have to use PNG anymore in your apps. Instead, you now use vector drawables.

That’s so cool. Your UI are well-designed, very smooth, and you don’t have to care to the dpi-variants of your icons anymore.

You’ve migrated all your icons to vector drawables in your app? Well done! But wait… have you tested your app on Android 5.0 Lollipop or previous? (such as ICS or KitKat ?)

Damn… your app crashes. Here are some guidelines to follow and to keep in mind to avoid industrial failure and droping a A-bomb on your user’s devices.

1. Use AppCompatResource to get your drawables

Okay, your app does not call context.getResources().getDrawable(…) anymore. That’s cool, you’re a good guy. It’s deprecated since a while.

But… do not use ContextCompat.getDrawable(context, …) either. It works for Android 5.0 and above, but not for lower versions of Android.

You shall use AppCompatResources.getDrawable(context, …) instead.

Good practice: use AppCompatResources everytime. Even if the drawable you’re loading is not a vector drawable.

2. Don’t get drawable directly from TypedArray

You’ve create a custom widget, with custom attrs. And you are passing a ‘drawable’ as a resource to this widget.

Do not get your drawable directly from your TypedArray. Retrieve the resource id first, then use AppCompatResources to get the drawable object.

Do:

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.xxx, defStyleAttr, 0);
int
drawableRes = ta.getResourceId(R.styleable.yyy, -1);
if (drawableRes != -1) {
Drawable drawable = AppCompatResources.getDrawable(getContext(), drawableRes);
if (drawable != null) {
...
}
}

Don’t:

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.xxx, defStyleAttr, 0);
Drawable drawable = ta.getDrawable(R.styleable.yyy);
if (drawable != null) {
...
}

3. Avoid scientific notation in your vector’s paths

If you import your own SVG file to a vector drawable using the embedded tool in Android Studio (or any other tool to convert SVG to vector drawable) please take care about what your vector’s paths contain.

Sometimes very small values are written in scientific notation, such as:

android:pathData="M 19.874333,2 6e-5,2 c -1.1442222,[...]"

6e-5 is the scientific notation for 0.00006. Avoid this notation for Android 5. and lower, it is not supported an will lead to a crash.

Easy to fix: replace them by their equivalent in decimal notation.

Good practice: in general if you import your own SVG (or if you convert your SVG to vector drawable by yourself or with a tool) always pay attention to the content of the paths. Same advice for the attributes, some of SVG attributes are not (yet?) supported by the vector drawable grammar.

4. Do not use android:src but rather app:src

In your layouts, use app:src instead of android:src (for your AppCompatImageView but also your ImageView widgets)

Good practice: as suggested in the comment on this article, in your XML, you can still use ImageView because the AppCompat tools will replace them by AppCompatImageView for you. But don’t forget to use app:srcCompat instead of android:src if you are applying a vector drawable.

5. Do not use vector drawable in selectors, TextView’s compound drawables…

Because it is not properly supported since AppCompat v23.4.0

But… there is a “magic” way to support that.

First up, this functionality was originally released in 23.2.0, but then we found some memory usage and Configuration updating issues so we it removed in 23.3.0. In 23.4.0 (technically a fix release) we’ve re-added the same functionality but behind a flag which you need to manually enable.

If you want re-enable this, just stick this line at the top of your Activity:

static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

But use it at your own risk. It may leads to memory usage problems and configuration updating issues.

6. To go further

Following is a very nice diagram that will answer you to the question “why the backward-compatible support for VectorDrawables comes with a price and doesn’t work in all cases?”

You can also read the original post by Chris Banes about the beginning of the age of the vectors:

https://medium.com/androiddevelopers/appcompat-v23-2-age-of-the-vectors-91cbafa87c88

--

--

Anthony Stéphan

Senior Android Developer (Freelance), funder of AS Mobile Development and developer of Printoid for OctoPrint (on Google Play)