问题背景
出问题的placeholder是一个ColorDrawable,对应色值的透明为100
- 实际展示时发现色值的透明度会有概率的发生变化,如:可能从FFE7E7E7 => 2FE7E7E7 或者 FFE7E7E7 => 57E7E7E7
- 同时一旦发生变化后,后续通过getResource#getDrawabke(resId)获取的资源的透明度也是错误的
![]() |
![]() |
---|
问题探究
1. 抓取问题特征
- ColorDrawable
- 透明度发生变化且取值随机
- 后续调用系统api获取的透明度也是错误的
2. 是否仅影响ColorDrawable?
一般使用中,占位图所使用的资源大都是ColorDrawable或者BitmapDrawable
线上发生问题的placeholder,改版前使用的是.9图,改版后使用的是colorDrawable
3. 对比发现
对比ColorDrawable,BitmapDrawable和NinePatchDrawable对于setAlpha方法的实现方式异同
-
ColorDrawable设置不同的alpha值会影响底层的ColorState,会导致后续通过getResource#getDrawabke(resId)获取的资源的透明度也是错误的
@Override public void setAlpha(int alpha) { alpha += alpha >> 7; // make it 0..256 final int baseAlpha = mColorState.mBaseColor >>> 24; final int useAlpha = baseAlpha * alpha >> 8; final int useColor = (mColorState.mBaseColor << 8 >>> 8) | (useAlpha << 24); if (mColorState.mUseColor != useColor) { mColorState.mUseColor = useColor; invalidateSelf(); } }
-
BitmapDrawable设置不同的alpha值会影响底层的BitmapState,理论上也会导致后续通过getResource#getDrawabke(resId)获取的资源的透明度也是错误的
@Override public void setAlpha(int alpha) { final int oldAlpha = mBitmapState.mPaint.getAlpha(); if (alpha != oldAlpha) { mBitmapState.mPaint.setAlpha(alpha); invalidateSelf(); } }
-
NinePatchDrawable设置不同的alpha值仅影响当前的drawable,并不会影响NinePatchState
@Override public void setAlpha(int alpha) { if (mPaint == null && alpha == 0xFF) { // Fast common case -- leave at normal alpha. return; } getPaint().setAlpha(alpha); invalidateSelf(); }
而线上改版前正是用的.9图,所以之前线上问题并不是很明显,更难发现
4. 排查问题来源
- 正常展示的网络图片时候,会发起一个从placeholder过渡至actualDrawable的渐变过程。
fresco的实现原理是包装一个FadeDrawable,不断修改其drawable的alpha值,修改的时候会默认先mutate一下,避免影响所有的drawable - 但如果在渐变过程中被中断并且下次这个hierarchy又被复用的时候,fresco会执行一个DrawableProperties的包括过程,相当于默认继承之前的drawable属性
而在这个过程中设置alpha时并没有对drawable进行mutate!!
//DrawableProperties
public void applyTo(Drawable drawable) {
if (drawable != null) {
if (this.mAlpha != -1) {
drawable.mutate().setAlpha(this.mAlpha);
}
... ...
}
}
问题解决
在知道问题根源后解决问题就比较简单了,在DrawableProperties设置alpha时进行下mutate。
具体实现方式:
- 整体重新编译源码
- 单独重新编译drawee
- 用字节码工具对aar进行修改
- 不修改源码的方式暂未找到,等待你的支持,哈哈
网友评论