Android获取Drawable对象方式为getResources().getDrawable(@DrawableResId int res), 只可能返回***Drawable、BitmapDrawable对象, 当然id不存在会抛异常。

public abstract class Drawable { ... }

Android Drawable缓存_第1张图片
在/framework/base/graphics/java/android/graphics目录下有很多Drawable派生类。
Android Drawable缓存_第2张图片

下面讲解下返回对象是如何产生的, 核心逻辑在ResourcesImpl.java

   private final DrawableCache mDrawableCache = new DrawableCache();  //缓存的是ConstantState抽象类的对象,而不是Drawable对象;  弱引用,不影响GC    private final DrawableCache mColorDrawableCache = new DrawableCache(); //弱引用,不影响GC        Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,            int density, @Nullable Resources.Theme theme)            throws NotFoundException {                 final boolean useCache = density == 0 || value.density == mMetrics.densityDpi;                 //getDrawableForDensity(id, 0, theme);density为0, 所以useCache默认为true,                   //app取自己的drawable时mPreloading为false, 即下面的if条件为真                if (!mPreloading && useCache) {                     final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);                     if (cachedDrawable != null) {                        cachedDrawable.setChangingConfigurations(value.changingConfigurations);                    return cachedDrawable;                }            }

不要被上面的caches.getInstance误导, 它创建了新的实例(newDrawble方法). 但是复用了ConstantState, 如果是BitmapDrawable的话就复用了Bitmap对象。

  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;    }       public Drawable newDrawable() {            return new BitmapDrawable(this, null);        }

做个练习:

BitmapDrawable firstDrawable = (BitmapDrawable) getResources()                .getDrawable(R.drawable.school_picture);BitmapDrawable secondDrawable = (BitmapDrawable) getResources()                .getDrawable(R.drawable.school_picture);

2个drawable实例指向的是同一个Bitmap对象(其实是Bitmap
State), 在操作其中一个drawble的时候, 另一个实例也会受影响。
Android Drawable缓存_第3张图片

如果想2个drawable互不影响, 即使用不同的ConstantState实例。 可以调用BitmapDrawable.java的mutate方法:

    @Override    public Drawable mutate() {        if (!mMutated && super.mutate() == this) {            mBitmapState = new BitmapState(mBitmapState);            mMutated = true;        }        return this;    }

即使用新的ConstantState实例替换mBitmapState参数值。

ResouresesImpl.java是通过文件后缀判断Drawable类型的, 如果后缀是xml则返回ColorDrawable对象, 否则返回BitmapDrawable对象。

private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,            int id, int density) {            ...            if (file.endsWith(".xml")) {                    final XmlResourceParser rp = loadXmlResourceParser(                            file, id, value.assetCookie, "drawable");                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null);                    rp.close();                } else {                    final InputStream is = mAssets.openNonAsset(                            value.assetCookie, file, AssetManager.ACCESS_STREAMING);                    AssetInputStream ais = (AssetInputStream) is;                    dr = decodeImageDrawable(ais, wrapper, value);   //返回BitmapDrawable                }    private Drawable decodeImageDrawable(@NonNull AssetInputStream ais,            @NonNull Resources wrapper, @NonNull TypedValue value) {        ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,                            wrapper, value);        try {            return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);            });        } catch (IOException ioe) {            // This is okay. This may be something that ImageDecoder does not            // support, like SVG.            return null;        }    }    public static Drawable decodeDrawable(@NonNull Source src,            @Nullable OnHeaderDecodedListener listener) throws IOException {        Bitmap bitmap = decodeBitmap(src, listener);        **return new BitmapDrawable(src.getResources(), bitmap);**    }

后缀是xml时,执行了Drawable.createFromXmlForDensity方法, 最终会执行到DrawableInflator.java的inflateFromTag方法, 返回上面graphics文件夹下面的类。。

    private Drawable inflateFromTag(@NonNull String name) {        switch (name) {            case "selector":                return new StateListDrawable();            case "animated-selector":                return new AnimatedStateListDrawable();            case "level-list":                return new LevelListDrawable();            case "layer-list":                return new LayerDrawable();            case "transition":                return new TransitionDrawable();            case "ripple":                return new RippleDrawable();            case "adaptive-icon":                return new AdaptiveIconDrawable();            case "color":                return new ColorDrawable();            case "shape":                return new GradientDrawable();            case "vector":                return new VectorDrawable();            case "animated-vector":                return new AnimatedVectorDrawable();            case "scale":                return new ScaleDrawable();            case "clip":                return new ClipDrawable();            case "rotate":                return new RotateDrawable();            case "animated-rotate":                return new AnimatedRotateDrawable();            case "animation-list":                return new AnimationDrawable();            case "inset":                return new InsetDrawable();            case "bitmap":                return new BitmapDrawable();            case "nine-patch":                return new NinePatchDrawable();            case "animated-image":                return new AnimatedImageDrawable();            default:                return null;        }    }

小结:
1、 getResources().getDrawable只可能返回Drawable(根据xml里的tag生成不同实例)、BitmapDrawable或者抛异常;
2、 在ResourcesImpl.java里缓存了ConstantState弱引用, 对应BitmapDrawable对象来说缓存了Bitmap引用。
3、通过调用drawable的mutate方法可以创建新的ConstantState对象。
4、ResourcesImpl.java通过文件名后缀返回不同的drawable对象, 后缀是xml时根据文件里的tag名称返回
Drawable对象,其它情况返回BitmapDrawable对象;
5、 在Activity、View退出时不需要解绑Drawable, 即ImageView的setImageDrawable(null)。 因为ResourcesImpl缓存的是Bitmap弱引用,可以被GC回收;

更多相关文章

  1. Android Http RequestCache缓存策略
  2. Android根据上下文对象Context找到对应的Activity
  3. Android解析json数组对象
  4. Android中的Parcel机制 实现Bundle传递对象
  5. Android 将从网络获取的数据缓存到私有文件
  6. Android 把从网络获取的图片缓存到内存中
  7. Android 多线程之synchronized锁住的是代码还是对象(二)
  8. Android Handler机制5之Message简介与消息对象对象池
  9. Android 对象序列化之你不知道的 Serializable

随机推荐

  1. android gif view
  2. Android中利用画图类和线程画出闪烁的心
  3. Android打造万能适配器--RecyclerView
  4. windows下android 开发环境建立
  5. android上类似iphone上的开关按钮
  6. Android: 添加shell命令行 alias配置
  7. Android Java basic knowledge ---AIDL2
  8. Android音量调节AudioManager
  9. Android SDCard操作(文件读写,容量计算)
  10. Android中的Animation使用