Binary XML file line #17<vector; tag requires viewportWidth ;0

Posted freeCodeSunny

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Binary XML file line #17<vector; tag requires viewportWidth ;0相关的知识,希望对你有一定的参考价值。

前言

       近期把项目中的support包升级到了26.1.0,看起来在手机上运行的稳稳的,没翻船!之后提交,测试就报了一个bug说5.0以下的手机都不能运行了!因此就排查了问题原因。

问题

       首先我们复现一下问题,看看崩溃日志,崩溃日志主要有以下两个:

E/VdcInflateDelegate: Exception while inflating <vector>
org.xmlpull.v1.XmlPullParserException: Binary XML file line #17<vector> tag requires viewportWidth > 0
  at android.support.graphics.drawable.VectorDrawableCompat.updateStateFromTypedArray(VectorDrawableCompat.java:690)
  at android.support.graphics.drawable.VectorDrawableCompat.inflate(VectorDrawableCompat.java:623)
  at android.support.graphics.drawable.VectorDrawableCompat.createFromXmlInner(VectorDrawableCompat.java:586)
  at android.support.v7.widget.AppCompatDrawableManager$VdcInflateDelegate.createFromXmlInner(AppCompatDrawableManager.java:777)
  at android.support.v7.widget.AppCompatDrawableManager.loadDrawableFromDelegates(AppCompatDrawableManager.java:365)
  at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:195)
  at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:188)
  at android.support.v7.widget.AppCompatDrawableManager.checkVectorDrawableSetup(AppCompatDrawableManager.java:755)
  at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:193)
  at android.support.v7.widget.TintTypedArray.getDrawableIfKnown(TintTypedArray.java:87)
  at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:128)
  at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:149)
  at android.support.v7.app.AppCompatDelegateImplV11.<init>(AppCompatDelegateImplV11.java:29)
  at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:54)
  at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:202)
  at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:183)
  at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:519)
  at com.xxx.common.activity.BaseActionBarActivity.installInflaterFactory(BaseActionBarActivity.java:192)
  at com.xxx.common.activity.BaseActionBarActivity.onCreate(BaseActionBarActivity.java:156)
  at com.xxx.activity.login.EntranceActivity.onCreate(EntranceActivity.java:64)
  at android.app.Activity.performCreate(Activity.java:5356)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1089)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2151)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2236)
  at android.app.ActivityThread.access$800(ActivityThread.java:138)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1199)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:136)
  at android.app.ActivityThread.main(ActivityThread.java:5122)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
  at dalvik.system.NativeStart.main(Native Method)   

       以及如下的错误,如下的错误会导致系统崩溃不能运行。

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xxx.debug, PID: 3565
java.lang.RuntimeException: Unable to start activity ComponentInfocom.xxx.debug/com.xxx.activity.login.EntranceActivity: android.content.res.Resources$NotFoundException: File res/drawable/abc_vector_test.xml from drawable resource ID #0x7f020052
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2187)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2236)
at android.app.ActivityThread.access$800(ActivityThread.java:138)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1199)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5122)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.content.res.Resources$NotFoundException: File res/drawable/abc_vector_test.xml from drawable resource ID #0x7f020052
at android.content.res.Resources.loadDrawable(Resources.java:2124)
at android.content.res.Resources.getDrawable(Resources.java:704)
at android.support.v7.widget.VectorEnabledTintResources.superGetDrawable(VectorEnabledTintResources.java:74)
at android.support.v7.widget.AppCompatDrawableManager.onDrawableLoadedFromResources(AppCompatDrawableManager.java:435)
at android.support.v7.widget.VectorEnabledTintResources.getDrawable(VectorEnabledTintResources.java:67)
at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:353)
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:200)
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:188)
at android.support.v7.widget.AppCompatDrawableManager.checkVectorDrawableSetup(AppCompatDrawableManager.java:755)
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:193)
at android.support.v7.widget.TintTypedArray.getDrawableIfKnown(TintTypedArray.java:87)
at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:128)
at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:149)
at android.support.v7.app.AppCompatDelegateImplV11.<init>(AppCompatDelegateImplV11.java:29)
at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:54)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:202)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:183)
at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:519)
at com.xxx.common.activity.BaseActionBarActivity.installInflaterFactory(BaseActionBarActivity.java:192)
at com.xxx.common.activity.BaseActionBarActivity.onCreate(BaseActionBarActivity.java:156)
at com.xxx.activity.login.EntranceActivity.onCreate(EntranceActivity.java:64)
at android.app.Activity.performCreate(Activity.java:5356)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1089)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2151)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2236) 
at android.app.ActivityThread.access$800(ActivityThread.java:138) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1199) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:136) 
at android.app.ActivityThread.main(ActivityThread.java:5122) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:515) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
at dalvik.system.NativeStart.main(Native Method) 
Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #17: invalid drawable tag vector
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:933)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:877)
at android.content.res.Resources.loadDrawable(Resources.java:2120)
at android.content.res.Resources.getDrawable(Resources.java:704) 
at android.support.v7.widget.VectorEnabledTintResources.superGetDrawable(VectorEnabledTintResources.java:74) 
at android.support.v7.widget.AppCompatDrawableManager.onDrawableLoadedFromResources(AppCompatDrawableManager.java:435) 
at android.support.v7.widget.VectorEnabledTintResources.getDrawable(VectorEnabledTintResources.java:67) 
at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:353) 
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:200) 
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:188) 
at android.support.v7.widget.AppCompatDrawableManager.checkVectorDrawableSetup(AppCompatDrawableManager.java:755) 
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:193) 
at android.support.v7.widget.TintTypedArray.getDrawableIfKnown(TintTypedArray.java:87) 
at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:128) 
at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:149) 
at android.support.v7.app.AppCompatDelegateImplV11.<init>(AppCompatDelegateImplV11.java:29) 
at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:54) 
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:202) 
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:183) 
at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:519) 
at com.xxx.common.activity.BaseActionBarActivity.installInflaterFactory(BaseActionBarActivity.java:192) 
at com.xxx.common.activity.BaseActionBarActivity.onCreate(BaseActionBarActivity.java:156) 
at com.xxx.activity.login.EntranceActivity.onCreate(EntranceActivity.java:64) 
at android.app.Activity.performCreate(Activity.java:5356) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1089) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2151) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2236) 
at android.app.ActivityThread.access$800(ActivityThread.java:138) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1199) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:136) 
at android.app.ActivityThread.main(ActivityThread.java:5122) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:515) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
at dalvik.system.NativeStart.main(Native Method) 

原因

       由于历史原因,以前做了很多分包的操作,因此gradle版本一直是1.2.3,不是当前最新的版本,因此写了一个Demo发现采用最新的版本不会出现崩溃。因此根据代码我们可以看到有如下执行路径:

日志1

       Activity继承自AppCompatActivity,在Activity加载的时候会调用到getDelegate()函数:

@NonNull
public AppCompatDelegate getDelegate() 
    if (mDelegate == null) 
        mDelegate = AppCompatDelegate.create(this, this);
    
    return mDelegate;

       最终会调用到create函数:

private static AppCompatDelegate create(Context context, Window window,
        AppCompatCallback callback) 
    if (Build.VERSION.SDK_INT >= 24) 
        return new AppCompatDelegateImplN(context, window, callback);
     else if (Build.VERSION.SDK_INT >= 23) 
        return new AppCompatDelegateImplV23(context, window, callback);
     else if (Build.VERSION.SDK_INT >= 14) 
        return new AppCompatDelegateImplV14(context, window, callback);
     else if (Build.VERSION.SDK_INT >= 11) 
        return new AppCompatDelegateImplV11(context, window, callback);
     else 
        return new AppCompatDelegateImplV9(context, window, callback);
    

       这里我们主要是5.0以下版本会崩溃,因此我们需要查看AppCompatDelegateImplV14,里面我们一直跟踪调用父类,最终会调用到如下的代码:

final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
context, null, sWindowBackgroundStyleable);
final Drawable winBg = a.getDrawableIfKnown(0);

       这里先解析是否有windowbackground属性,并且获取对应的drawable:

public Drawable getDrawableIfKnown(int index) 
    if (mWrapped.hasValue(index)) 
        final int resourceId = mWrapped.getResourceId(index, 0);
        if (resourceId != 0) 
            return AppCompatDrawableManager.get().getDrawable(mContext, resourceId, true);
        
    
    return null;

       这里recouseId不等于0,进入到AppCompatDrawableManager.中的getDrawable函数:

Drawable getDrawable(@NonNull Context context, @DrawableRes int resId,
        boolean failIfNotKnown) 
    checkVectorDrawableSetup(context);

    Drawable drawable = loadDrawableFromDelegates(context, resId);
    if (drawable == null) 
        drawable = createDrawableIfNeeded(context, resId);
    
    if (drawable == null) 
        drawable = ContextCompat.getDrawable(context, resId);
    

    if (drawable != null) 
        // Tint it if needed
        drawable = tintDrawable(context, resId, failIfNotKnown, drawable);
    
    if (drawable != null) 
        // See if we need to 'fix' the drawable
        DrawableUtils.fixDrawable(drawable);
    
    return drawable;

       getDrawable函数中首先调用了checkVectorDrawableSetup(context)函数:

private void checkVectorDrawableSetup(@NonNull Context context) 
    if (mHasCheckedVectorDrawableSetup) 
        // We've already checked so return now...
        return;
    
    // Here we will check that a known Vector drawable resource inside AppCompat can be
    // correctly decoded
    mHasCheckedVectorDrawableSetup = true;
    final Drawable d = getDrawable(context, R.drawable.abc_vector_test);
    if (d == null || !isVectorDrawable(d)) 
        mHasCheckedVectorDrawableSetup = false;
        throw new IllegalStateException("This app has been built with an incorrect "
                + "configuration. Please configure your build for VectorDrawableCompat.");
    

       我们发现上面有一个资源R.drawable.abc_vector_test,这个系统support包里的Vector资源,我们先来看看他的xml:


<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportHeight="24.0"
        android:viewportWidth="24.0">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M20,11L7.8,11l5.6,-5.6L12,4l-8,8l8,8l1.4,-1.4L7.8,13L20,13L20,11z"/>
</vector>

       我们继续往下看,这里初始状态为false,因此会继续往下执行,首先改为了true,并且继续调用了上面的getDrawable函数,因为这里改为了true,因此会进入的到getDrawable函数中的loadDrawableFromDelegates:


private Drawable loadDrawableFromDelegates(@NonNull Context context, @DrawableRes int resId) 
    if (mDelegates != null && !mDelegates.isEmpty()) 
         ............................
        if (tv.string != null && tv.string.toString().endsWith(".xml")) 
            // If the resource is an XML file, let's try and parse it
            try 
                final XmlPullParser parser = res.getXml(resId);
                final AttributeSet attrs = Xml.asAttributeSet(parser);
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) 
                    // Empty loop
                
                if (type != XmlPullParser.START_TAG) 
                    throw new XmlPullParserException("No start tag found");
                

                final String tagName = parser.getName();
                // Add the tag name to the cache
                mKnownDrawableIdTags.append(resId, tagName);

                // Now try and find a delegate for the tag name and inflate if found
                final InflateDelegate delegate = mDelegates.get(tagName);
                if (delegate != null) 
                    dr = delegate.createFromXmlInner(context, parser, attrs,
                            context.getTheme());
                
                if (dr != null) 
                    // Add it to the drawable cache
                    dr.setChangingConfigurations(tv.changingConfigurations);
                    if (addDrawableToCache(context, key, dr) && DEBUG) 
                        Log.i(TAG, "[loadDrawableFromDelegates] Saved drawable to cache: " +
                                context.getResources().getResourceName(resId));
                    
                
             catch (Exception e) 
                Log.e(TAG, "Exception while inflating drawable", e);
            
        
    .............
        return dr;
    

    return null;

       这里我们先删除了部分代码,只看最重要的部分,那就是delegate.createFromXmlInner,实际调用的是VectorDrawableCompat
.createFromXmlInner(context.getResources(), parser, attrs, theme),继续调用createFromXmlInner中的inflate函数,inflate中继续调用到updateStateFromTypedArray:

private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser)
        throws XmlPullParserException 
    final VectorDrawableCompatState state = mVectorState;
    final VPathRenderer pathRenderer = state.mVPathRenderer;

    // Account for any configuration changes.
    // state.mChangingConfigurations |= Utils.getChangingConfigurations(a);

    final int mode = TypedArrayUtils.getNamedInt(a, parser, "tintMode",
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_TINT_MODE, -1);
    state.mTintMode = parseTintModeCompat(mode, Mode.SRC_IN);

    final ColorStateList tint =
            a.getColorStateList(AndroidResources.STYLEABLE_VECTOR_DRAWABLE_TINT);
    if (tint != null) 
        state.mTint = tint;
    

    state.mAutoMirrored = TypedArrayUtils.getNamedBoolean(a, parser, "autoMirrored",
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_AUTO_MIRRORED, state.mAutoMirrored);

    pathRenderer.mViewportWidth = TypedArrayUtils.getNamedFloat(a, parser, "viewportWidth",
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_WIDTH,
            pathRenderer.mViewportWidth);

    pathRenderer.mViewportHeight = TypedArrayUtils.getNamedFloat(a, parser, "viewportHeight",
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_HEIGHT,
            pathRenderer.mViewportHeight);

    if (pathRenderer.mViewportWidth <= 0) 
        throw new XmlPullParserException(a.getPositionDescription() +
                "<vector> tag requires viewportWidth > 0");
     else if (pathRenderer.mViewportHeight <= 0) 
        throw new XmlPullParserException(a.getPositionDescription() +
                "<vector> tag requires viewportHeight > 0");
    

    pathRenderer.mBaseWidth = a.getDimension(
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_WIDTH, pathRenderer.mBaseWidth);
    pathRenderer.mBaseHeight = a.getDimension(
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_HEIGHT, pathRenderer.mBaseHeight);
    if (pathRenderer.mBaseWidth <= 0) 
        throw new XmlPullParserException(a.getPositionDescription() +
                "<vector> tag requires width > 0");
     else if (pathRenderer.mBaseHeight <= 0) 
        throw new XmlPullParserException(a.getPositionDescription() +
                "<vector> tag requires height > 0");
    

    // shown up from API 11.
    final float alphaInFloat = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
            AndroidResources.STYLEABLE_VECTOR_DRAWABLE_ALPHA, pathRenderer.getAlpha());
    pathRenderer.setAlpha(alphaInFloat);

    final String name = a.getString(AndroidResources.STYLEABLE_VECTOR_DRAWABLE_NAME);
    if (name != null) 
        pathRenderer.mRootName = name;
        pathRenderer.mVGTargetsMap.put(name, pathRenderer);
    

       这里调用TypedArrayUtils.getNamedFloat会去解析viewportWidth与viewportHeight:

public static float getNamedFloat(@NonNull TypedArray a, @NonNull XmlPullParser parser,
        @NonNull String attrName, @StyleableRes int resId, float defaultValue) 
    final boolean hasAttr = hasAttribute(parser, attrName);
    if (!hasAttr) 
        return defaultValue;
     else 
        return a.getFloat(resId, defaultValue);
    


   public static boolean hasAttribute(@NonNull XmlPullParser parser, @NonNull String attrName) 
    return parser.getAttributeValue(NAMESPACE, attrName) != null;

       这里会发现viewportHeight与viewportWidth不存在,但是我们上面的xml里明明有这两个属性,为什么到这个地方就没有了?

gradle 1.2.3调用aapt编译资源,因为VectorDrawable是21才加入的,因此他不认识这两个属性,被优化掉了,同时优化掉的还有path中的内容

       由于上面的原因,xml在编译后viewportWidth与viewportHeight会移除了,因此在解析的时候返回了0,系统检测该值,抛出了异常!

  • 为什么23的版本不崩溃

23版本的内容未做检查,不会调用checkVectorDrawableSetup函数

日志2

       上面有两个日志,第一个日志我们已经清楚了,只是抛出了异常,而不会导致崩溃,那为什么系统会崩溃,我们看到上面日志的下半部分与日志1相同,所以原因也是一样的,我们继续往下看loadDrawableFromDelegates解析失败后drawable为空,会继续执行createDrawableIfNeeded,这里只是对想要资源做了检查,因此最终会调用到ContextCompat.getDrawable中:

public static final Drawable getDrawable(Context context, @DrawableRes int id) 
    if (Build.VERSION.SDK_INT >= 21) 
        return context.getDrawable(id);
     else if (Build.VERSION.SDK_INT >= 16) 
        return context.getResources().getDrawable(id);
     else 
        // Prior to JELLY_BEAN, Resources.getDrawable() would not correctly
        // retrieve the final configuration density when the resource ID
        // is a reference another Drawable resource. As a workaround, try
        // to resolve the drawable reference manually.
        final int resolvedId;
        syn

以上是关于Binary XML file line #17<vector; tag requires viewportWidth ;0的主要内容,如果未能解决你的问题,请参考以下文章

InflateException: Binary XML file line #8: Error inflating class ImageView

在测试类中膨胀 ViewBinding 时出错:Binary XML file line #38: Binary XML file line #38: Error inflating class &l

Binary XML file line #8 in 包名路经:layout/layout文件名字: Binary XML file line #8 in 包名路经:layout/layout文件名字

Binary XML file line #2: Error inflating

Binary XML file line 2: Error inflating class

android.view.InflateException: Binary XML file line #7: Error inflating class(OOM)