项目中有这样一个场景,不同界面的多个ImageView,展示同一个drawable资源,但是页面根据自身的scroll位置不同,设置了不同的alpha值。
初始代码如下:
imageView.setImageResource(resId);
imageView.setAlpha(alpha);
在实际测试中发现,多个页面加载同一Drawable的不同ImageView的表现一致,即均展示了统一的alpha(最后一次调用设置的alpha值)的效果。
原因是默认情况下,同一资源id加载的所有Drawable实例,共享同一状态。Drawable可使用mutate方法来解决上述问题。该方法说明如下。
/**
* Make this drawable mutable. This operation cannot be reversed. A mutable
* drawable is guaranteed to not share its state with any other drawable.
* This is especially useful when you need to modify properties of drawables
* loaded from resources. By default, all drawables instances loaded from
* the same resource share a common state; if you modify the state of one
* instance, all the other instances will receive the same modification.
*
* Calling this method on a mutable Drawable will have no effect.
*
* @return This drawable.
* @see ConstantState
* @see #getConstantState()
*/
public Drawable mutate() {
return this;
}
mutate方法让drawable可变的,保证了与其他drawable的状态隔离,该操作不可逆。解决方案如下:
Drawable drawable = getResources().getDrawable(resId);
imageView.setImageDrawable(drawable.mutate());
imageView.getDrawable().setAlpha(255*alpha);
Android内部针对相同资源使用了缓存机制DrawableCache,缓存的信息是Drawable.CommonState,其中BitmapDrawable中BitmapState就是CommonState的实现类。
/**
* If the resource is cached, creates and returns a new instance of it.
*
* @param key a key that uniquely identifies the drawable resource
* @param resources a Resources object from which to create new instances.
* @param theme the theme where the resource will be used
* @return a new instance of the resource, or {@code null} if not in
* the cache
*/
@UnsupportedAppUsage
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;
}
BitmapState提供了newDrawable方法返回BitmapDrawable,且相同资源的BitmapDrawable对象共用同一个BitmapState,二者互相持有对象引用。setAlpha操作改变的就是BitmapDrawable的mBitmapState对象的属性值。这才导致上面的问题。
在尝试上述解决方案时,最初imageView一直未能未显示图片。原来是xml中设置了alpha属性为0,即imageView全透明。删除改行,动态设置alpha即可。
参考文章:
android Drawable.mutate()的使用
Android:关于Drawable的缓存机制应该了解的知识