Desc
Drawable 是对某些内容可以被 draw 下来的抽象;
最常用的就是将资源文件绘制到屏幕上,比如 src、background 等;
与 View 不同的是,Drawable 不能接收任何输入事件或者其他与用户的交互事件,就单纯是用来绘制内容的;
Reuse
Drawable 中实现了一套复用机制,当从同一份资源文件加载出来的多个 Drawable 对象,都会共享同一份 ConstantState;
ConstantState 是 Drawable 的内部抽象类,用于存储 Drawable 之间共享的 constant state 和数据;比如 BitmapDrawable 会共享同一个 bitmap;
因此 Drawable 是实现 draw 绘制逻辑,而 ConstantState 用于存放绘制的内容;
这样的复用机制会导致一种情况:
多个从同一个资源文件中加载的 Drawable 对象
对其中一个修改其属性,比如 color、alpha 属性,都会影响到其他所有对象;
Implementation
ResourcesImpl#loadDrawable
资源的加载是由 Resources 类完成,最终会走到 ResourcesImpl#loadDrawable 方法;
最开始的一步就是从缓存中检索
// First, check whether we have a cached version of this drawable
// that was inflated against the specified theme. Skip the cache if
// we're currently preloading or we're not using the cache.
if (!mPreloading && useCache) {
final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
if (cachedDrawable != null) {
cachedDrawable.setChangingConfigurations(value.changingConfigurations);
return cachedDrawable;
}
}DrawableCache#getInstance 实现:
get是检索缓存方法,而拿到的结果是ConstantState对象Drawable 对象是通过
ConstantState#newDrawable方法创建出来的;
public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
final Drawable.ConstantState entry = get(key, theme);
if (entry != null) {
return entry.newDrawable(resources, theme);
}
return null;
}如果不是从缓存检索的对象(缓存能拿到会直接返回),会走到这一步,将结果 dr (可能新创建或者预加载)缓存起来
// If we were able to obtain a drawable, store it in the appropriate
// cache: preload, not themed, null theme, or theme-specific. Don't
// pollute the cache with drawables loaded from a foreign density.
if (dr != null) {
dr.setChangingConfigurations(value.changingConfigurations);
if (useCache) {
cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
if (needsNewDrawableAfterCache) {
Drawable.ConstantState state = dr.getConstantState();
if (state != null) {
dr = state.newDrawable(wrapper);
}
}
}
}Example
GradientDrawable
以该类为示例:
GradientState.newDrawable 是直接将 state 传入新的 GradientDrawbale 对象中;
@Override
public Drawable newDrawable(@Nullable Resources res) {
// If this drawable is being created for a different density,
// just create a new constant state and call it a day.
final GradientState state;
final int density = Drawable.resolveDensity(res, mDensity);
if (density != mDensity) {
state = new GradientState(this, res);
} else {
state = this;
}
return new GradientDrawable(state, res);
}setColor:修改的是 GradientState 对象中的属性,因此会影响到其他使用该 GradientState 的 GradientDrawable 实例;
public void setColor(@ColorInt int argb) {
mGradientState.setSolidColors(ColorStateList.valueOf(argb));
mFillPaint.setColor(argb);
invalidateSelf();
}mutate 方法:新创建一个 GradientState,而不是和其他的进行共享;
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mGradientState = new GradientState(mGradientState, null);
updateLocalState(null);
mMutated = true;
}
return this;
}