• decodeResource


    getResources().getDrawable(id)

    会执行

     public Drawable getDrawable(int id) throws NotFoundException {
            synchronized (mTmpValue) {
                TypedValue value = mTmpValue;
                getValue(id, value, true);
                return loadDrawable(value, id);
            }
        }
      1     /*package*/ Drawable loadDrawable(TypedValue value, int id)
      2             throws NotFoundException {
      3 
      4         if (TRACE_FOR_PRELOAD) {
      5             // Log only framework resources
      6             if ((id >>> 24) == 0x1) {
      7                 final String name = getResourceName(id);
      8                 if (name != null) android.util.Log.d("PreloadDrawable", name);
      9             }
     10         }
     11 
     12         final long key = (((long) value.assetCookie) << 32) | value.data;
     13         boolean isColorDrawable = false;
     14         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
     15                 value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
     16             isColorDrawable = true;
     17         }
     18         Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
     19 
     20         if (dr != null) {
     21             return dr;
     22         }
     23 
     24         Drawable.ConstantState cs = isColorDrawable ?
     25                 sPreloadedColorDrawables.get(key) : sPreloadedDrawables.get(key);
     26         if (cs != null) {
     27             dr = cs.newDrawable(this);
     28         } else {
     29             if (isColorDrawable) {
     30                 dr = new ColorDrawable(value.data);
     31             }
     32 
     33             if (dr == null) {
     34                 if (value.string == null) {
     35                     throw new NotFoundException(
     36                             "Resource is not a Drawable (color or path): " + value);
     37                 }
     38 
     39                 String file = value.string.toString();
     40 
     41                 if (TRACE_FOR_MISS_PRELOAD) {
     42                     // Log only framework resources
     43                     if ((id >>> 24) == 0x1) {
     44                         final String name = getResourceName(id);
     45                         if (name != null) android.util.Log.d(TAG, "Loading framework drawable #"
     46                                 + Integer.toHexString(id) + ": " + name
     47                                 + " at " + file);
     48                     }
     49                 }
     50 
     51                 if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
     52                         + value.assetCookie + ": " + file);
     53 
     54                 if (file.endsWith(".xml")) {
     55                     try {
     56                         XmlResourceParser rp = loadXmlResourceParser(
     57                                 file, id, value.assetCookie, "drawable");
     58                         dr = Drawable.createFromXml(this, rp);
     59                         rp.close();
     60                     } catch (Exception e) {
     61                         NotFoundException rnf = new NotFoundException(
     62                             "File " + file + " from drawable resource ID #0x"
     63                             + Integer.toHexString(id));
     64                         rnf.initCause(e);
     65                         throw rnf;
     66                     }
     67 
     68                 } else {
     69                     try {
     70                         InputStream is = mAssets.openNonAsset(
     71                                 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
     72         //                System.out.println("Opened file " + file + ": " + is);
     73                         dr = Drawable.createFromResourceStream(this, value, is,
     74                                 file, null);
     75                         is.close();
     76         //                System.out.println("Created stream: " + dr);
     77                     } catch (Exception e) {
     78                         NotFoundException rnf = new NotFoundException(
     79                             "File " + file + " from drawable resource ID #0x"
     80                             + Integer.toHexString(id));
     81                         rnf.initCause(e);
     82                         throw rnf;
     83                     }
     84                 }
     85             }
     86         }
     87 
     88         if (dr != null) {
     89             dr.setChangingConfigurations(value.changingConfigurations);
     90             cs = dr.getConstantState();
     91             if (cs != null) {
     92                 if (mPreloading) {
     93                     if (isColorDrawable) {
     94                         sPreloadedColorDrawables.put(key, cs);
     95                     } else {
     96                         sPreloadedDrawables.put(key, cs);
     97                     }
     98                 } else {
     99                     synchronized (mTmpValue) {
    100                         //Log.i(TAG, "Saving cached drawable @ #" +
    101                         //        Integer.toHexString(key.intValue())
    102                         //        + " in " + this + ": " + cs);
    103                         if (isColorDrawable) {
    104                             mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
    105                         } else {
    106                             mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
    107                         }
    108                     }
    109                 }
    110             }
    111         }
    112 
    113         return dr;
    114     }

    请注意18行,这里我们会去尝试读取CachedDrawable,看看这里是否有我们需要读取的Drawable。显然,第一次读取的时候,是不会存在缓存。所以我们继续往下看。

     1  private Drawable getCachedDrawable(long key) {
     2         synchronized (mTmpValue) {
     3             WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
     4             if (wr != null) {   // we have the key
     5                 Drawable.ConstantState entry = wr.get();
     6                 if (entry != null) {
     7                     //Log.i(TAG, "Returning cached drawable @ #" +
     8                     //        Integer.toHexString(((Integer)key).intValue())
     9                     //        + " in " + this + ": " + entry);
    10                     return entry.newDrawable(this);
    11                 }
    12                 else {  // our entry has been purged
    13                     mDrawableCache.delete(key);
    14                 }
    15             }
    16         }
    17         return null;
    18     }

    关键是73行,这里会从资源中创建一个Drawable对象。这个函数最终会调用到drawableFromBitmap(),其中会new BitmapDrawable(res, bm):

    1     public BitmapDrawable(Resources res, Bitmap bitmap) {
    2         this(new BitmapState(bitmap), res);
    3         mBitmapState.mTargetDensity = mTargetDensity;
    4     }

    请注意,我们创建了一个BitmapState对象。

    继续看loadDrawable()函数,来到90行,这里,我们会把新的Drawable的ConstantState加入到缓存中。这个ConstantState对于BitmapDrawable来说,实际就是一个BitmapState对象

    final static class BitmapState extends ConstantState {
    }

    然后,我们就完成第一次读取BitmapDrawable对象。

     如果我们再次读取这个BitmapDrawable对象,回头看loadDrawable()的第18行,我们会从CachedDrawable中拿:

     1     private Drawable getCachedDrawable(
     2             LongSparseArray<WeakReference<ConstantState>> drawableCache,
     3             long key) {
     4         synchronized (mTmpValue) {
     5             WeakReference<Drawable.ConstantState> wr = drawableCache.get(key);
     6             if (wr != null) {   // we have the key
     7                 Drawable.ConstantState entry = wr.get();
     8                 if (entry != null) {
     9                     //Log.i(TAG, "Returning cached drawable @ #" +
    10                     //        Integer.toHexString(((Integer)key).intValue())
    11                     //        + " in " + this + ": " + entry);
    12                     return entry.newDrawable(this);
    13                 }
    14                 else {  // our entry has been purged
    15                     drawableCache.delete(key);
    16                 }
    17             }
    18         }
    19         return null;
    20     }

    请看12行,对于BitmapDrawable的BitmapState来说,newDrawable()就是:

    1         @Override
    2         public Drawable newDrawable(Resources res) {
    3             return new BitmapDrawable(this, res);
    4         }

    看到什么了?对了,两次读取到的Drawable共享了一个BitmapState。其实,所有的ConstantState都是共享的。NinePatchDrawable中的ConstantState,即NinePatchState,也是共享的。

    那问题出在哪儿?请注意这个名字ConstantState。实际上,Drawable的设计者希望,能够共享给所有Drawable使用的state都必须是Constant的。但是,不幸的是BitmapDrawable的设计者却不打算遵循这个规范。请回头看看本文开始的地方写的BitmapDrawable的alpha是通过BitmapState的Paint来实现的。而BitmapState是共享的。也就是说同一个BitmapDrawable的alpha值是共享的!!而NinePatchDrawable就没有这个问题,其alpha设置并不共享。

    会造成什么问题?

    假设你有两个一样的Button,使用了BitmapDrawable作为背景,当你对某一个Button做alpha动画的时候,实际上另外一个Button的alpha值也在变化!!!但是因为另外一个Button没有重绘,所以你看不到,如果这个时候某一个事件导致界面重绘,比如锁屏再解锁,就会发现另外一个Button的alpha值也变化了。

    所以,请慎用BitmapDrawable,最好不要用他来做alpha动画。当然,也不仅是alpha值才有这个问题,所有BitmapState中共享的值都会存在这个问题。请看:

    1         Bitmap mBitmap;
    2         int mChangingConfigurations;
    3         int mGravity = Gravity.FILL;
    4         Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
    5         Shader.TileMode mTileModeX = null;
    6         Shader.TileMode mTileModeY = null;
    7         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
    8         boolean mRebuildShader;
  • 相关阅读:
    【转】日本留学——修士申请注意事项
    【转】日本留学读研究生和修士有什么区别?申请误区有哪些
    【转】为什么说学一门小语种,就能打开新世界的大门?
    【转】TED:两年一门外语--她总结了学外语的秘诀
    【转】为什么一定要学一门外语?
    【转】学完标准日本语初级至高级,可以过日语n1吗?
    【转】去日本语言学校前,日语应该达到几级呢?
    Cordova学习
    敏捷开发实录(二)
    Mac端博客发布工具推荐
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/3042719.html
Copyright © 2020-2023  润新知