现象
Support包升级到23.3.0后,在5.0之前的机器上,对ImageView设置src,或者对AppCompatImageView设置app:srcCompat(item为vector的select资源),应用程序会crash。
根据Google的介绍:
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 [https://goo.gl/u5suZB, https://goo.gl/fW5Tyd]. Using app:srcCompat and setImageResource() continues to work.
由于存在bug,在23.3.0中已经移除了在pre-Lollipop设备上使用资源获取vector drawable的支持。
分析
根据应用的crash报告:
Caused by android.content.res.Resources$NotFoundException
android.content.res.Resources.loadDrawable (Resources.java:1923)
android.content.res.Resources.getDrawable (Resources.java:664)
android.graphics.drawable.StateListDrawable.inflate (StateListDrawable.java:173)
android.graphics.drawable.Drawable.createFromXmlInner (Drawable.java:867)
以上为部分堆栈
select对应到会创建StateListDrawable实例,并会分析该xml中的item创建相应的drawable。
我们都知道,当我们使用Support包时并将我们的Activity继承AppCompatActivity时,在setContentView的时候会使用AppCompatViewInflater来创建View,将TextView实例化成AppCompatTextView,将ImageView实例化成AppCompatImageView。
而在AppCompatImageView的构造函数中,会通过TintContextWrapper来使用TintResources劫持Resouces的getDrawable方法。
而在23.2.0中,该方法的代码如下:
@Override
public Drawable getDrawable(int id) throws NotFoundException {
return AppCompatDrawableManager.get().onDrawableLoadedFromResources(mContext, this, id);
}
会直接调用AppCompatDrawableManager.get,使得在5.0之前的版本也支持vectorDrawable。
而在23.3.0中,该方法代码修改如下:
@Override
public Drawable getDrawable(int id) throws NotFoundException {
Drawable d = super.getDrawable(id);
Context context = mContextRef.get();
if (d != null && context != null) {
AppCompatDrawableManager.get().tintDrawableUsingColorFilter(context, id, d);
}
return d;
}
会先调用super的getDrawable方法,由于在5.0之前的版本中,Drawable找不到vector标签,抛出了NotFoundException导致应用的crash。
而5.0之后的版本,Drawable已经支持vector表情的解析了,所以不存在这个问题。