16

I'm having some problems with Android Studio at the moment because I recently started using "Vector Assets". I've done absolutely everything necessary to display them correctly in my application (using the app:srcCompat="" in the xml, android {defaultConfig {vectorDrawables.useSupportLibrary true}} in the build.gradle, and AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); in the onCreate() method before setContentView()).

The svg files I imported into Android Studio do not have errors themselves, I can see the result without any problem in an ImageView with the wizard. The only problem comes when I run my application and it arrives at the time to draw the svg. Some of my svg's still work, while others don't, so I think some of them take too long to process. Here is the error :

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.retroverse.bataille_corse, PID: 18807
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.retroverse.bataille_corse/com.retroverse.bataille_corse.MenuPrincipal}: android.view.InflateException: Binary XML file line #127: Binary XML file line #127: Error inflating class ImageView
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2985)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3120)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1840)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6872)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
     Caused by: android.view.InflateException: Binary XML file line #127: Binary XML file line #127: Error inflating class ImageView
     Caused by: android.view.InflateException: Binary XML file line #127: Error inflating class ImageView
     Caused by: android.content.res.Resources$NotFoundException: Drawable com.retroverse.bataille_corse:drawable/card_49_en with resource ID #0x7f060099
     Caused by: android.content.res.Resources$NotFoundException: File res/drawable/card_49_en.xml from drawable resource ID #0x7f060099
        at android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:854)
        at android.content.res.ResourcesImpl.loadDrawable(ResourcesImpl.java:634)
        at android.content.res.MiuiResourcesImpl.loadDrawable(MiuiResourcesImpl.java:329)
        at android.content.res.Resources.getDrawableForDensity(Resources.java:902)
        at android.content.res.Resources.getDrawable(Resources.java:841)
        at android.content.Context.getDrawable(Context.java:644)
        at androidx.core.content.ContextCompat.getDrawable(ContextCompat.java:454)
        at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:144)
        at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:132)
        at androidx.appcompat.content.res.AppCompatResources.getDrawable(AppCompatResources.java:104)
        at androidx.appcompat.widget.AppCompatImageHelper.loadFromAttributes(AppCompatImageHelper.java:59)
        at androidx.appcompat.widget.AppCompatImageView.<init>(AppCompatImageView.java:78)
        at androidx.appcompat.widget.AppCompatImageView.<init>(AppCompatImageView.java:68)
        at androidx.appcompat.app.AppCompatViewInflater.createImageView(AppCompatViewInflater.java:187)
        at androidx.appcompat.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:107)
        at androidx.appcompat.app.AppCompatDelegateImpl.createView(AppCompatDelegateImpl.java:1407)
        at androidx.appcompat.app.AppCompatDelegateImpl.onCreateView(AppCompatDelegateImpl.java:1457)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:734)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:867)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:828)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:519)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:427)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
        at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:555)
        at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:161)
        at com.retroverse.bataille_corse.MenuPrincipal.onCreate(MenuPrincipal.java:24)
        at android.app.Activity.performCreate(Activity.java:7232)
E/AndroidRuntime:     at android.app.Activity.performCreate(Activity.java:7221)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2965)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3120)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1840)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6872)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
     Caused by: java.lang.IllegalArgumentException: R is not a valid verb. Failure occurred at position 2 of path: STRING_TOO_LARGE
        at android.util.PathParser.nCreatePathDataFromString(Native Method)
        at android.util.PathParser.access$200(PathParser.java:24)
        at android.util.PathParser$PathData.<init>(PathParser.java:76)
        at android.graphics.drawable.VectorDrawable$VFullPath.updateStateFromTypedArray(VectorDrawable.java:2016)
        at android.graphics.drawable.VectorDrawable$VFullPath.inflate(VectorDrawable.java:1967)
        at android.graphics.drawable.VectorDrawable.inflateChildElements(VectorDrawable.java:819)
        at android.graphics.drawable.VectorDrawable.inflate(VectorDrawable.java:717)
        at android.graphics.drawable.DrawableInflater.inflateFromXmlForDensity(DrawableInflater.java:142)
        at android.graphics.drawable.Drawable.createFromXmlInnerForDensity(Drawable.java:1332)
        at android.graphics.drawable.Drawable.createFromXmlForDensity(Drawable.java:1291)
        at android.content.res.ResourcesImpl.createFromXmlForDensity(ResourcesImpl.java:1506)
        at android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:838)
            ... 41 more

The most important line, I think, is Caused by: java.lang.IllegalArgumentException: R is not a valid verb. Failure occurred at position 2 of path: STRING_TOO_LARGE. We also know that this svg was caught in the middle (its size is 187 kilobytes). So I think my SVG file (even imported in Android Studio by "Vector Asset") is too heavy. As we are told here, the STRING_TOO_LARGE issue appears when the string "is longer than 0x7FFF = 32767 characters". (In the reproduction part) Indeed, the only svg to work in my application are lighter than 32 kb, which could explain this.

But I really need to display this svg (don't offer to convert it to png!) correctly, and if possible without optimizing its paths. Any help would be welcome!

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
TheBigBadBoy
  • 611
  • 5
  • 14
  • What have you tried so far? Does the SVG file contain any line breaks? If not, have you tried adding any? – r3mainer May 18 '20 at 19:49
  • The problematic line (#127) is a strokeColor attribute in a , but has no error. If I use the same svg file by deleting several (until it is below 32 kb), I can display it without any problem. As said before, the file itself doesn't have any error (nor warning), the problem comes only when you draw a too heavy svg (surely). I hope to find a way around this mistake, still using the same svg. – TheBigBadBoy May 19 '20 at 09:57
  • I tried using a layer-list with the svg divided into several items, but nothing works... – TheBigBadBoy May 21 '20 at 19:00
  • I'm afraid I'm rather stumped. The 32kb limit does seem quite lame. Perhaps you could split the SVG into multiple files somehow? – r3mainer May 21 '20 at 20:00
  • After spending some time on it and trying several ways, here is the only one that works: I imported several times the same svg with the Vector Asset function, and then split the vector into parts (I cut each part just before the problematic line). I took all these vector pieces and put them together in a layer-list. These vector pieces are now less than 10kb, and drawing the layer-list works perfectly without any errors. I'll keep you posted to see how many kb I get an error from (always by splitting the svg). The only problem is that it takes a crazy amount of time... – TheBigBadBoy May 22 '20 at 13:59
  • Finally, I did a little test right away, and as long as the svg pieces don't exceed about 30kb, there's no problem. The error indicates a certain line in the xml (vector), but this is actually not the limit to display for the vector (basically, I left the so-called error at line #127 and kept a bigger part of the vector, all without exceeding 32kb). Because of the , I can't correctly cut stack at 32kb, that's why I say "about". – TheBigBadBoy May 22 '20 at 14:11
  • Perhaps you could turn your findings into an answer. Have an upvote anyway. – r3mainer May 22 '20 at 14:21

2 Answers2

20

I found the answer (at last...).

Actually, there is no real problem with Vector Assets over 32 kb, it all depends on what is in the code. I should have paid more attention to the warnings than usual I don't always look at...

I discovered inside my svg a path data with a path of more than 40kb (in one string so). The fact is that, according to the site in the question, a String can't have more than (about) 32k characters or the whole string used in any xml file will be replaced by "STRING_TOO_LARGE". Anyway, by just removing this line here, I can draw the vector perfectly well (while it is still 250 kb, but now incomplete).

What's quite surprising is that Android Studio only displays a warning (where the string is longer than 32k characters) just to make me understand that an svg with a long path can be slow to display, instead of warning me that the path will be corrupted because it's too long (or even better turn this warning into an error in the IDE, to avoid an unpleasant surprise).

TheBigBadBoy
  • 611
  • 5
  • 14
  • 4
    which line? in "this line here" – htafoya Jul 06 '20 at 15:49
  • 1
    I meant by removing the tag `` where `android:pathData` was "STRING_TOO_LARGE" but consequently the vector is no longer complete. The best that remains to be done is to divide the path into several different "subpaths". – TheBigBadBoy Jul 06 '20 at 19:23
13

Thanks to @TheBigBadBoy I splitted long SVG path into several segments. I opened XML file of the image and divided the path by M symbol (see also how to split one path into two paths in svg).

<path
    android:fillColor="#ffffff"
    android:fillType="evenOdd"
    android:pathData="M40.255,47.8897C40.1686, ... ,47.8897ZM38.7713,40.2642L38.8362, ..., 46.0978Z"
    />

enter image description here

You can see that each segment starts with M and ends with Z. You can retain about 20Kb in the first path and cut the tail. Then paste the tail into the second path. Make so many paths that all of them become less than 32 Kb.

So, you will get:

<path
    android:fillColor="#ffffff"
    android:fillType="evenOdd"
    android:pathData="M40.255,47.8897C40.1686, ... ,47.8897Z"
    />

<path
    android:fillColor="#ffffff"
    android:fillType="evenOdd"
    android:pathData="M38.7713,40.2642L38.8362, ..., 46.0978Z"
    />
CoolMind
  • 26,736
  • 15
  • 188
  • 224