Desc

Drawable 是对某些内容可以被 draw 下来的抽象;

最常用的就是将资源文件绘制到屏幕上,比如 src、background 等;

与 View 不同的是,Drawable 不能接收任何输入事件或者其他与用户的交互事件,就单纯是用来绘制内容的;

Reuse 

Drawable 中实现了一套复用机制,当从同一份资源文件加载出来的多个 Drawable 对象,都会共享同一份 ConstantState

ConstantStateDrawable 的内部抽象类,用于存储 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;
 }