Using android vector Drawables on pre Lollipop crash
Asked Answered
N

17

96

I'm using vector drawables in android prior to Lollipop and these are of some of my libraries and tool versions:

  • Android Studio : 2.0
  • Android Gradle Plugin : 2.0.0
  • Build Tools : 23.0.2
  • Android Support Library : 23.3.0

I added this property in my app level Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

It is also worth mentioning that I use an extra drawable such as LayerDrawable(layer_list) as stated in Android official Blog (link here) for setting drawables for vector drawables outside of app:srcCompat

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/search"/>
</level-list>

You’ll find directly referencing vector drawables outside of app:srcCompat will fail prior to Lollipop. However, AppCompat does support loading vector drawables when they are referenced in another drawable container such as a StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable, and RotateDrawable. By using this indirection, you can use vector drawables in cases such as TextView’s android:drawableLeft attribute, which wouldn’t normally be able to support vector drawables.

When I'm using app:srcCompat everything works fine, but when I use:

android:background
android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom

on ImageView, ImageButton, TextView or EditText prior to Lollipop, it throws an expection:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9
Northernmost answered 26/4, 2016 at 14:4 Comment(4)
Possible duplicate of Android vector compatibilityGumma
To see how use VectorDrawable with drawableLeft, drawableRight, drawableTop, drawableBottom check out This answerNorthernmost
Can you check my answer here? https://mcmap.net/q/112254/-how-to-use-vectordrawables-in-android-api-lower-than-21Languor
In my case, vactor drawables weren't in right package (open project view) orginal answer here https://mcmap.net/q/219143/-vectordrawablecompat-resources-notfoundexception-on-kitkat-and-belowBurd
R
112

LATEST UPDATE - Jun/2019

Support Library has changed a bit since the original answer. Now, even the Android plugin for Gradle is able to automatically generate the PNG at build time. So, below are two new approaches that should work these days. You can find more info here:

PNG Generation

Gradle can automatically create PNG images from your assets at build time. However, in this approach, not all xml elements are supported. This solution is convenient because you don't need to change anything in your code or in your build.gradle. Just make sure you are using Android Plugin 1.5.0 or higher and Android Studio 2.2 or higher.

I'm using this solution in my app and works fine. No additional build.gradle flag necessary. No hacks is necessary. If you go to /build/generated/res/pngs/... you can see all generated PNGs.

So, if you have some simple icon (since not all xml elements are supported), this solution may work for you. Just update your Android Studio and your Android plugin for Gradle.

Support Library

Probably, this is the solution that will work for you. If you came here, it means your Android Studio is not generating the PNGs automatically. So, your app is crashing.

Or maybe, you don't want Android Studio to generate any PNG at all.

Differently from that "Auto-PNG generation" which supports a subset of XML element, this solution, supports all xml tags. So, you have full support to your vector drawable.

You must first, update your build.gradle to support it:

android {
  defaultConfig {
    // This flag will also prevents Android Studio from generating PNGs automatically
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  // Use this for Support Library
  implementation 'com.android.support:appcompat-v7:23.2.0' // OR HIGHER

  // Use this for AndroidX
  implementation 'androidx.appcompat:appcompat:1.1.0' // OR HIGHER
}

And then, use app:srcCompat instead of android:src while loading VectorDrawables. Don't forget this.

For TextView, if you are using the androidx version of the Support Library, you can use app:drawableLeftCompat (or right, top, bottom) instead of app:drawableLeft

In case of CheckBox/RadioButton, use app:buttonCompat instead of android:button.

If you are not using the androidx version of the Support Library and your minSdkVersion is 17 or higher or using a button, you may try to set programmatically via

Drawable icon = AppCompatResources.getDrawable(context, <drawable_id>);
textView.setCompoundDrawablesWithIntrinsicBounds(<leftIcon>,<topIcon>,<rightIcon>,<bottomIcon>);

UPDATE - Jul/2016

They re-enabled that VectorDrawable in
Android Support Library 23.4.0

For AppCompat users, we’ve added an opt-in API to re-enable support Vector Drawables from resources (the behavior found in 23.2) via AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - keep in mind that this still can cause issues with memory usage and problems updating Configuration instances, hence why it is disabled by default.

Maybe, build.gradle setting is now obsolete and you just need to enable it in proper activities (however, need to test).

Now, to enable it, you must do:

public class MainActivity extends AppCompatActivity {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

    ...
}

Original Answer - Apr/2016

I think this is happening because Support Vector was disabled in the latest library version: 23.3.0

According to this POST:

For AppCompat users, we’ve decided to remove the functionality which let you use vector drawables from resources on pre-Lollipop devices due to issues found in the implementation in version 23.2.0/23.2.1 (ISSUE 205236). Using app:srcCompat and setImageResource() continues to work.

If you visit issue ISSUE 205236, it seems that they will enable in the future but the memory issue will not be fixed soon:

In the next release I've added an opt-in API where you can re-enable the VectorDrawable support which was removed. It comes with the same caveats as before though (memory usage and problems with Configuration updating).

I had a similar issue. So, in my case, I reverted all icons which use vector drawable from resource to PNG images again (since the memory issue will keep happening even after they provide an option to enable it again).

I'm not sure if this is the best option, but it fixes all the crashes in my opinion.

Rainband answered 27/4, 2016 at 19:42 Comment(19)
Thanks @Guilherme P. but why didn't you removed the vectorDrawables.useSupportLibrary = true peroperty to go back to enabling generating pngs at build time again?Northernmost
Oh Sorry if I was not clear... I did not removed that tag from build.gradle.. I meant, I deleted all vectors_images.xml from drawable folder and replace them by PNG icons (like I was using in the past)... In my case, I was using vector drawable in place of some icons...Rainband
I know. but even though without the tag from build.gradle, pre lollipop androids should be able use vector drawables by generating pngs at build time? doesn't it?Northernmost
That was disabled in latest version v23.3.0 due to memory issues. This way, they can not generate png at runtime... That's why in the logcat error they print: unknown tag vector (or something like that).Rainband
Thanks for explanation. in my case srcCompat is enough for most layouts and until a proper fix, I going to replace drawable_left ,right & ... with a LinearLayout and ImageView.Northernmost
Here is the opt-in instructions plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX. Unfortunately VectorDrawables are still not working on Pre-Lollipop device. I'm on Support Library 23.4.0 and have both 'generatedDensities = []' and 'vectorDrawables.useSupportLibrary = true' called in defaultConfig{}.Gumma
any luck with this? facing the same issue. I'm using 23.4.0 and have the option enabled...no joyReneta
@Gumma I updated the answer.. It seems that it was enabled again.. However, you must enable it differently now.Rainband
@Reneta I updated the answer.. It seems that it was enabled again.. However, you must enable it differently now.Rainband
@GuilhermeP - In order to have backwards compatibility for Vector Drawables here is the following configuration I used for API Level pre-20 devices. build.gradle: vectorDrawables.useSupportLibrary = true [new line] dependencies{classpath 'com.android.tools.build:gradle:2.1.2'} Activity: onCreate > AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); XML ImageView: app:srcCompat="@drawable/vector"Gumma
To see how use VectorDrawable with drawableLeft, drawableRight, drawableTop, drawableBottom check out This answerNorthernmost
Also don't forget to put your files into the "drawable" folder, rather than in "drawable-anydpi"!Snavely
you might wanna try this approach as well from medium: android.jlelse.eu/…Cerography
simply adding drawableRight programmatically solved my issueHankow
Thanks a million for excellent explanation.I used app:drawableStartCompat insted of android:drawableStart and problem solved without adding vectorDrawables.useSupportLibrary = true to defaultConfig.Is it necessary to add it?Diplomatic
@W0rmH0le , adding implementation 'com.android.support:appcompat-v7:23.2.0' won't do if you're using androidx, this is only if you're using the support library, right?Langobardic
@Langobardic You're right. You should use 'androidx.appcompat:appcompat:1.1.0'Rainband
this answer has become very confusing, contains a lot of unnecessary information and does not provide a useful solution.Immeasurable
I agree about the confusing due the updates. But nevertheless the magic was using app:drawableLeftCompat (or any other of that kind) I did not know about them. Thank you.Oddment
O
65

I had the same problem. But doing a lot of R&D I got the answer.

For Imageview and ImageButton use,app:srcCompat="@drawable/...." and for other views like Button, Textview, instead of using "drawableLeft/right..." in the XML, specify drawables programmitically as :

button.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(mContext,R.drawable.ic_share_brown_18dp), null, null, null);

And use "AppCompatResources" to get the drawable.

Oby answered 25/7, 2017 at 10:5 Comment(0)
U
60

To elaborate on the other very good answers, here is a diagram that can help you. It is valid if you have Support Library from 23.4.0 to at least 25.1.0.

VectorDrawable cheatsheet

Unspent answered 25/1, 2017 at 17:23 Comment(2)
in case you are trying to set drawableLeft wrap it inside a drawable as mentioned here. medium.com/@chrisbanes/…Gerfalcon
Thank you this chart help us a lot.Trine
G
39

The answer from Guillherme P is pretty awesome. Just to make a small improvement, you don't need to add that line in every activity, if you added it once in the Application class it will work as well.

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

REMEMBER: You still need to have enabled the use of the support library in gradle:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Also, make sure you are using a support library version greater than v23.4, when Google added back the support for Drawable Containers for VectorDrawables (release note)

Update

And for code changes:

  1. Make sure to update to app:srcCompat every place that accepts the android:src attribute (the IDE will warn you if it's invalid like for the <bitmap> tag).
  2. For drawableLeft, drawableStart, drawableRight, drawableEnd attributes used in TextView and similar views, you will have to set them programmatically for now. An example of setting drawableStart:

    Drawable drawable = AppCompatResources.getDrawable(
            getContext(),
            R.drawable.your_vector_drawable);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
    }
    
Gloxinia answered 3/9, 2016 at 0:41 Comment(3)
remember that you need to have ON the use of the support library for vector drawables in gradle: vectorDrawables.useSupportLibrary = trueGloxinia
Yep. I know. But there is necessary a wrapper to make vector drawables work as drawables for TexViews, so this answer is incomplete.Blurt
Great answer. It is particularly good for apps with all of its activities extended from a custom base activity.Selfsatisfied
B
15

I had the same problem. And fix it by removing

vectorDrawables.useSupportLibrary = true

My target version is 25 and support library is

 compile 'com.android.support:appcompat-v7:25.3.1'
Blasted answered 12/9, 2017 at 11:21 Comment(3)
this worked for me. Thanks. I just removed that vectorDrawables.useSupportLibrary = trueLayoff
I think this is not the proper way to do it, Either way I gave upvote to your answer.!!Corker
Thank you. t works for my app. All vector drawables still work if it has been removed. The app uses com.android.support:appcompat-v7:28.0.0Selfsatisfied
B
11

VectorDrawables on pre-lollipop should work fine without using

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

If you want to use VectorDrawables inside ImageViews, you can use the attribute srcCompat and it will work, but inside Buttons or TextViews it won't, so you need to wrap the Drawable into an InsetDrawable or a LayerDrawable. There is another trick I discovered, if you are using data binding, you could do this:

android:drawableLeft="@{@drawable/vector_ic_access_time_24px}"
android:drawableStart="@{@drawable/vector_ic_access_time_24px}"

That will magically work, I haven't investigated what's happening behind the scenes, but I guess the TextView is using the getDrawable method from the AppCompatResources or similar.

Blurt answered 23/11, 2016 at 10:4 Comment(2)
How to set vector image in selector?Gibeonite
after setting vectorDrawables.useSupportLibrary = true in gradle default and AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); in activity on create To avoid crash with android:drawableleft in Textview, set drawble left to the textview programitically for examlple: textview.setCompoundDrawablesWithIntrinsicBounds(R.drawable.movie, 0, 0, 0);Changeful
C
10

Lot of R & d, finally getting this solution for crashes on pre-lollipop devices.

For Imageview

  • use app:srcCompat instead of android:src

For TextView/EditText

  • Remove drawableleft,drawableright.... and set from drawable java code.

txtview.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(EventDetailSinglePage.this, R.drawable.ic_done_black_24_n), null, null, null);

For Build.gradle

vectorDrawables.useSupportLibrary = true

Clayson answered 15/8, 2018 at 7:9 Comment(2)
It was the unique solution that worked on TextInputEditText.Titbit
Awsome , this is solved my problem .This should be accepted answer.Lungfish
D
8

Easiest way use :

app:drawableRightCompat ="@drawable/ic_mobilelogin"
app:drawableEndCompat="@drawable/ic_mobilelogin"
app:srcCompat="@drawable/ic_mobile"

and... just use app:**Compatfor compatability. Also add support on build.gradle (module)

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}
Distinguish answered 23/12, 2018 at 15:33 Comment(1)
app:drawableEndCompat and app:drawableRightCompat is pretty much the same thing if its englishPhilender
I
5

For anyone who upgrade to android gradle 3.0 and above, there is no need to use AppCompatDelegate.setCompatVectorFromResourcesEnabled(true), or set vectorDrawables.useSupportLibrary = true (add this will cause problem) and use app:srcCompat, it just works.

Take me two days to figure this out, and have not find any related docs in google's docs...

Incompletion answered 7/12, 2017 at 8:11 Comment(1)
Interesting, I'm using gradle 3.3.0 and this solution works. However, Android Studio is still telling me to enable set vectorDrawables.useSupportLibrary = true.Tailback
T
3

After using the below code.

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




public class App extends Application {
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}}

still, vector images issue exists for below attributes are

DrawableEnd, DrawableStart, DrawableTop, DrawableBottom, Background

In this case, please follow as below, Instead of referencing vector image directly use selector tag as an intermediate drawable file.

Example:

ic_warranty_icon.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="17"
android:viewportHeight="24">

<path
    android:fillColor="#fff"
    android:pathData="M10.927,15.589l-1.549,0.355a7.47,7.47 0,0 1,-0.878 0.056c-4.136,0 -7.5,-3.364 -7.5,-7.5s3.364,-7.5 7.5,-7.5 7.5,3.364 7.5,7.5c0,3.286 -2.126,6.078 -5.073,7.089zM8.5,2a6.508,6.508 0,0 0,-6.5 6.5c0,3.583 2.917,6.5 6.5,6.5s6.5,-2.917 6.5,-6.5 -2.917,-6.5 -6.5,-6.5z" />

safe_ic_warranty_icon.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warranty_icon"  />
</selector>

Your TextView/Layout.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableStart="@drawable/ic_warranty_icon"
       />


<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_warranty_icon"
       />
Thymic answered 2/7, 2019 at 10:6 Comment(2)
Thanks !!! For background property, adding selector in between rather than directly using vector drawable worked for pre-lollipop api (19).Zelig
in my case, this still doesn't work for API (16), even wrapping with selectorCerography
M
3

We tried 3 things

vectorDrawables.useSupportLibrary = true

Setting setCompatVectorFromResourcesEnabled in Application class

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

And use app:srcCompat

But even after that it was failing with

Resources$NotFoundException: File res/drawable/$my_icon__0.xml from color state list resource ID #0x7f080008

then we figured out that our SVG had a Gradient tag. Converting the gradient tag to individual paths for below API <= 23 and using the same SVG API >= 24 worked.

Got help from this answer https://mcmap.net/q/219144/-lt-gradient-gt-tag-inside-xml-causes-android-to-crash

Moonshot answered 31/7, 2019 at 11:41 Comment(1)
I don't know why no one upvote this, but this could actually be the solution to my problem. Thank youLandry
C
2

I am using VectorDrawables on Pre-lollipop devices and this is how I do it :-

Step 1: Put this in your app level gradle.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Step 2:

Put this in your Application class and don't forget to register your Application class in the manifest file.

public class App extends Application {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
}

Step 3:

Get VectorDrawables using,

imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.my_vector_drawable));
Coopersmith answered 30/9, 2017 at 6:34 Comment(0)
A
1

I was struggling with this for hours.

I tried everything these answers told me to, but my app didn't stop crashing. I deleted this line: app:srcCompat="@drawable/keyboard" and my app stopped crashing. and then when I added this same thing back, it started crashing again. So I decided to open that file and I saw an error at the first line saying

"The drawable 'Keyboard' has no declaration in the base drawable folder; this can lead to crashes.

I right-clicked the file and clicked "Show in explorer" and it was not in the drawable folder but in the drawable-v24 directory. So I copied it and pasted to the drawable directory and finally got rid of crashes.

Aleutian answered 28/2, 2020 at 17:14 Comment(0)
S
0

Simply overlap vector drawable to state-list then problem will be solved

For example you have back arrow vector image:

ic_back_arrow.xml

yes, you should overlap it to layer list xml (ic_back_arrow_vector_vector.xml):

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_back_arrow"/>
</layer-list>

Because logic:

vectorDrawables.useSupportLibrary = true

and

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

will not help you on the some China devices and older samsung devices. If you do not overlap them, it will fail.

Solleret answered 26/10, 2018 at 6:59 Comment(0)
C
0

In my case, I was using a TabLayout, which I configured as it :

TabLayoutMediator(tabLayout!!, viewPager!!) { tab, position ->
    if (position == 0)
        tab.icon = ResourcesCompat.getDrawable(resources, R.drawable.ic_list, theme)
    else
        tab.icon = ResourcesCompat.getDrawable(resources, R.drawable.ic_building_map, theme)
}.attach()

The app was crashing at line tab.icon = ...

I change these to tab.setIcon(R.drawable.my_vector_asset), as it :

TabLayoutMediator(tabLayout!!, viewPager!!) { tab, position ->
    if (position == 0)
        tab.setIcon(R.drawable.ic_list)
    else
        tab.setIcon(R.drawable.ic_building_map)
}.attach()

And it worked !

Crushing answered 5/11, 2021 at 16:34 Comment(0)
V
-2

Guilherme P's suggestion was not working for me. I went ahead and made the decision to use png's where I need to do things outside of app:srcCompat i.e. drawableLeft, drawableRight, etc. This was a pretty easy change to make, and doesn't have the potential memory issues AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); introduces.

Versicular answered 27/3, 2017 at 17:6 Comment(0)
L
-3

An alternative to Benny's answer is to create an Activity superclass:

public abstract class VectorDrawableActivity extends AppCompatActivity {
  static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
  }

  //...
}

Now extend VectorDrawableActivity instead of AppCompatActivity.

Laski answered 10/11, 2016 at 2:5 Comment(1)
@Blurt Why not?Laski

© 2022 - 2024 — McMap. All rights reserved.