原文来自Android SDK文档中的resources/articles/drawable-mutations.html

Android的drawables非常便于构建应用。Drawable是一个可插拨的绘制容器(drawing container), 通常与一个View关联。 比如, BitmapDrawable用于显示图片, ShapeDrawable用于绘制图形和渐变, 等等。 还可以组合使用,创建更复杂的渲染效果。

Drawables允许不必继承Widget就可以方便地定制Widget的渲染效果。事实上, 它们是如此方便易用,多数自带的Android应用和Widget是通过使用Drawables来构建的。 Android核心框架使用了大约700个Drawables。由于Drawables的系统中大量使用, Android优化过其加载过程。比如, 每次当你创建一个Button, 一个新的Drawable将从框架资源文件中(android.R.drawable.btn_default)加载进来。 这意味着所有应用中所有的button使用不同的Drawable实例作为它们的背景。 但是所有这些Drawables共享相同的状态, 即Constant State。 这个状态中的内容因使用的Drawable类型而变化,但通常都包含所有可用的资源属性。 以button为例,Constant State包含一个Bitmap Image。 这样,所有应用中的所有Button都共享相同的Bitmap, 可以节省大量内存。 下图展示当把同一个Image资源作为两个不同的View的背景时哪些实体将被创建。 正如你所见, 两个Drawable被创建,但他们共享同一个Constant State, 即同一个Bitmap 虽然共享Constant State这个特性有利于减少内存的使用, 但当你需要修改Drawable的属性时可能产生问题。 考虑一个应用, 它有一个Book列表。 每个Book书名旁边有一个星形, 当用户标记当前Book为喜欢时这个星形完全不透明, 而未标记为喜欢时这个星形为半透明。 为实现这个显示效果, list adapter中的getView()方法可以这样写:
Book book = ...;TextView listItem = ...;listItem.setText(book.getTitle());Drawable star = context.getResources().getDrawable(R.drawable.star);if (book.isFavorite()) {  star.setAlpha(255); // opaque} else {  star.setAlpha(70); // translucent}
很不幸, 以上代码将产生奇怪的结果:所有的星形都成了半透明。如下图所示: 这个结果也说明了Constant State的特点。 尽管我们为每个Item生成了一个新的Drawable实例, Constant State仍然是相同的。 对BitmapDrawable而言, 透明度也是Constant State的一部分。因此, 改变一个Drawable实例的透明度, 同时也会影响其他Drawable实例的透明度。 更糟糕的是, 这个问题在Android 1.0和Android 1.1上不容易修复。 Android 1.5及以上版本提供了一个简单的办法来解决这个问题:新添加的mutate()方法。当你在某个Drawable上调用mutate()方法时, 将复制该Drawable的Constant State, 并允许修改该复制结果的属性且不会对其他Drawable生成影响。 注意, 就算复制了Drawable, Drawable仍然共享Bitmap。 下图显示了在Drawable上调用mutate()之后的结果: 现在, 使用mutate()重新修改一下之前的代码:
Drawable star = context.getResources().getDrawable(R.drawable.star);if (book.isFavorite()) {  star.mutate().setAlpha(255); // opaque} else {  star. mutate().setAlpha(70); // translucent}
mutate()方法返回Drawable自己, 所以链式调用非常方便。 这个方法并没有创建一个新的Drawable实例。 修改后的代码结果是正确的。 (另外附上自己根据这篇文档写的一个例子, 验证下mutate()的用法) 代码:
public class ConstantStateActivity extends ListActivity {private ListAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mAdapter = new MyListAdapter(this, R.layout.my_adatper, R.id.textView1, Arrays.asList("and-aa", "iphone-b"));getListView().setAdapter(mAdapter);}static class MyListAdapter extends ArrayAdapter<String> {private int mRes;private List<String> mData;public MyListAdapter(Context context, int resource,int textViewResourceId, List<String> objects) {super(context, resource, textViewResourceId, objects);this.mRes = resource;this.mData = objects;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = convertView;if (null == view) {LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(LAYOUT_INFLATER_SERVICE);view = inflater.inflate(mRes, parent, false);ImageView icon = (ImageView) view.findViewById(R.id.imageView1);MyLog.i(icon + "");if (mData.get(position).startsWith("and")) {icon.getDrawable().setAlpha(0);//icon.getDrawable().mutate().setAlpha(0);}}return view;}}}
布局:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent" android:layout_height="fill_parent"android:gravity="center_vertical"><ImageView android:layout_height="wrap_content" android:src="@drawable/icon"android:layout_width="wrap_content" android:id="@+id/imageView1"></ImageView><TextView android:text="TextView" android:id="@+id/textView1"android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView></LinearLayout>
不调用mutate()时截图如下(ImageView都变成透明的了, 所以看不见) 调用mutate()方法时截图如下(一个ImageView透明, 另一个不透明, 正确结果!)

更多相关文章

  1. Android(安卓)中Preferences的使用!
  2. Android(安卓)- Android(安卓)Studio 自动(auto)添加import 语句
  3. android SharedPreferences 使用
  4. Android使用系统方法实现分享到QQ和微信!
  5. android后台运行服务,加验证
  6. Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. Android(安卓)Studio 单刷《第一行代码》
  2. Android模拟神器――Genymotion
  3. Android(五)数据存储之五网络数据交互
  4. android应用程序基本原理
  5. Android(安卓)vector矢量图应用实例
  6. Android数据加密之SHA安全散列算法
  7. Android(安卓)NDK r4 windows 环境中的安
  8. IDEA搭建Android(安卓)wear开发环境,Andro
  9. android:layout_weight总有你不知道的用
  10. Android系统Surface机制的SurfaceFlinger