BitmapDrawable.mutate()

BitmapDrawable有了更深的认识后才发现有点错怪了Google那帮家伙,其实他们也早就意识到原文所提到的问题了,虽然做出补救是在SDK1.5才出现的,那就是BitmapDrawable.mutate()这个方法。

原来Resources缓存的并不是个Drawable,而是Drawable中的State(比如BitmapDrawableBitmapState)。是这个State起了一个share的作用,导致不同的Drawable产生了关联。而mutate就是重新创建一个State以避免共享。所以当要修改alpha时,只要mutate()后再修改即可。

而如果要在SDK 1.5以下的版本回避这个问题,则可以采用下面原文所提的方法。

然而,这个问题目前对于我来说已经很小儿科了,又出现了更头疼的问题,希望我能解决并分享解决方案。

 

===========================以下是原文=============================

阅读之前要建立一个信念:Android就是一个给工程师折腾的东西(外观和用户体验也是),文档什么的只是浮云,更多的时候你只能去源码里折腾,否则你根本不知道Google那帮家伙到底写了啥逻辑。

问题1:我用ImageView A做了个按钮,(用id引用drawable中的图片a),并做了个半透明效果(通过setAlpha),当用户Touch这个A时才不透明。现在我在另一处地方也需要用到图片a(不需要半透明行为),也是建立了一个新ImageView B并用id引用。然后你看看最终显示效果,会发现AB保持着同样的外观,也就是要么AB一样不透明,要么BA一样半透明。

解答:首先不说别的,单纯吐槽一下,两个独立的ImageView仅仅因为引用了同样一张图片,就产生了关联,设计API和背后的机制不是这么玩的啊……好吧,为了性能吧,有经验的立刻会想到,存在一个cache机制来确保每一个程序resource中的图片只被加载一次且只生成一个Drawable,并且AB都引用了同一个Drawable。而setAlpha会改变背后的Drawable,于是AB的外观会保持一样。

那么这个cache是否能被关闭呢?看看API,提供了不少跟cache有关的方法哦,什么setDrawingCacheEnabled,什么setWillNotCacheDrawing,什么destroyDrawingCache,不过首先心一悬,这些方法都是来自View的,而且ImageView并未override;紧接着你进行试验,以上三个方法全部搭上,然后毫无效果。

好吧,看源码吧,看这个cache到底是在哪进行的。看啊看,在ImageView源码的resolveUri函数中找到了答案,就是下面这句话:

d = rsrc.getDrawable(mResource);

这句话的意思是说,如果你是通过id引用drawable中的图片,那么会从rsrc(一个Resource对象)中来获取Drawable。于是明白了,是Resource进行了这个cache(哎早就该想到)。

那怎么绕过这个cache呢?API不用指望了,Resource的这个cache行为粗看了下源码貌似是必须的(而且在大多数应用场景下是有利的)。所以应该对于需要修改图片透明度的ImageView,强制地创建新的Drawable。只讨论ImageViewDrawableBitmapDrawable的情况,通过((BitmapDrawable)ImageView.getDrawable()).getBitmap()可以提取Bitmap,然后再new个新的BitmapDrawable并给ImageView重新setImageDrawable即可解决。

当然更高效的做法,是对需要修改ImageView透明度的控件,实现一个你自己的Drawable缓存,只要这些ImageView不是同时出现在屏幕上即可。

 

转载自  http://sgzxy.blog.163.com/blog/static/1509728222010112703010/

 

你可能感兴趣的:(android)