“Very Long Vector Path” issues… and where to find them.

A few weeks ago I was working on the Android app we have at M-KOPA Solar and I experienced this frustrating situation where easy things suddenly get complicated >_<.

The task was easy, update some of the icons of the app, rely on Material Design icons, import them into Android Studio as Vector Drawables and… that’s it…

Well, that was not it. By the time I opened my Pull Request and our automated Static Analysis task finished running one of our tools, Sonar, left a comment on one of the vector Drawables lines… Android Lint was saying the path of the icon was too long :(

At that point, my first thought was: ”That’s unfortunate, I just downloaded the icon from the official website, I thought they are optimised already :(”.

My second thought was: “I will check with my team, probably it is not the first time this happens”.

The first approach, Vector Drawable optimiser.

After checking and running a few searches on StackOverflow I found a Vector Drawable optimiser called Avocado which was used quite heavily for optimising the Vector Drawable so I decided to go for it.

$ avocado ic_settings.xml -o ic_settings.xml

Output:

ic_settings.xml:
Done in 10 ms!
1.961 Kb —
9.1% = 1.782 Kb

Great! It did optimise it, How long is it now?

We went down from 1746 chars to 1589… that’s a good improvement, but it seems it is not enough.

The second approach, SVG Optimiser

My assumption that the SVG was optimised already had to be wrong. So I decided to try another option a team member shared, SVGO the SVG optimiser.

$ svgo settings-24px.svg -o settings-24px.svg

Output:

settings-24px.svg:
Done in 16 ms!
1.409 KiB — 5.4% = 1.333 KiB

Run avocado again:

$ avocado ic_settings.xml -o ic_settings.xml

Output:

ic_settings.xml:
Done in 16 ms!
1.881 Kb — 8.9% =
1.714 Kb

Import it to Android Studio:

The size of the Vector Drawable went down a bit… is that enough? F**** I'm getting a bit hopeless here and I start to blame the Material icon I downloaded again… why couldn’t it be optimised already? U_U

The third approach, What about precision?

Again during our endless chat about this in the team, the point about “tweaking precision” on the SVG optimiser comes up. Hum… that’s interesting. Let me try and see what’s the result.

I use this time and online SVG Optimiser using svgo underneath and the result looks quite promising. If I tweak the precision to 1, the file size reduction is 61%, down it to 886 bytes.

And If I optimise it with Avocado (will skip showing the output this time) and import it to Android Studio…

Damn it! Still not enough… why?

The forth approach, Understand how far do I need to go optimising it? And why is that long?

I like to believe it is never too late to do something… but this probably should have been the first approach of all… however I didn’t think of it cause I was too optimistic thinking the tools would solve the problem quickly for me :D

One of my teammates (thanks Paul Blundell) mentioned that it would be nice to understand what’s the max length that LINT allows (Why didn’t I think of that myself? :/)… that and also suggested inspecting visually the vector points, to identify any redundant bits we can reduce using a Vector Path editor.

First question, how long is an acceptable vector path for LINT?

This one was easy to answer. According to the VectorPathDetector declared inside Lint (thanks Xavi Rigau for giving us a talk about custom Lint rules a few days before this), the max length should be 800 chars. Great, last optimisation showed a length of 926

Second question, can I reduce the Vector path points to achieve 800 chars?

I copy-pasted the vector path from Android Studio to the Vector Path Editor I started to look at it in detail…

Before optimising manually.

As you can see there are some weird points not aligned properly, and I also noticed some corners with redundant points placed together. Those seemed not necessary so I decided to remove those. Good.

I realised that the inner line of the dents, had super subtle curved lines with 4 points each and I changed it by straight lines instead. Great.

I spent like 1h to apply manual tweaks while I was squeezing my eyes super hard to avoid messing up with the icon appearance or miss a potential improvement.

After optimising the points manually.

And after removing points placed together, removing middle points in “almost” straight lines and … I ended up having a quite optimised icon path and I decided to stop there.

When I pasted the Vector path to the Vector Drawable xml on Android Studio, I ran avocado and wait for LINT to complain again…

Wait… what? No complaints? Yay! I checked the path length and it was 786 chars, just below the 800 chars threshold. So happy :D

Conclusion

In the end, the icon was optimised and it didn’t compromise the appearance… but it took more than I ever expected it would.

So… lesson learnt, my takeaways from that day (which I hope to remember more often from now on with the help of this article) are:

  • This worked this time because of the nature and size of the icon and the screen where it is displayed. The icon and the screen is small enough to not compromise the appearance, however, this might be quite difficult to achieve with a more detailed icon or a bigger icon.
  • If you are breaking a rule (In this case Lint rule), understand why first, check the source code.
  • Don’t rely on your assumptions straight away, at least double-check what you are looking it and make sure what you think is right.
  • You can double-check your assumptions, using data and visual aids which are always helpful to look under the hood of things. Just use them… I never heard any saying “I regret understanding what this method does”, or “I regret using the Layout Inspector” :P.

Software Enginner — Android passionate — Runner addict — Photography lover

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