原文来自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  Android SDK文档之Drawable Mutations 虽然共享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}
很不幸, 以上代码将产生奇怪的结果:所有的星形都成了半透明。如下图所示:  Android SDK文档之Drawable Mutations 这个结果也说明了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()之后的结果:  Android SDK文档之Drawable Mutations 现在, 使用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实例。 修改后的代码结果是正确的。  Android SDK文档之Drawable Mutations (另外附上自己根据这篇文档写的一个例子, 验证下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都变成透明的了, 所以看不见)  Android SDK文档之Drawable Mutations 调用mutate()方法时截图如下(一个ImageView透明, 另一个不透明, 正确结果!)
 Android SDK文档之Drawable Mutations

更多相关文章

  1. Android使用系统方法实现分享到QQ和微信!
  2. Android多种方法获取系统时间
  3. intelliJ IDEA 创建maven android工程的方法
  4. Android5.1系统通过包名给应用开放系统权限的方法
  5. Android MP4取得播放时长的方法
  6. Android中执行java命令的方法及java代码执行并解析shell命令
  7. Android 导入项目时报Android.jar包丢失解决方法
  8. 干货 | 聊聊这些年总结的一些学习方法
  9. Android手机访问Django测试服务器方法

随机推荐

  1. Stuff about Android
  2. Android 自动更新代码
  3. BBC发布了android客户端应用
  4. Android 键盘设计
  5. Android FTP Server
  6. Build your first Android Application w
  7. Android睡眠统计图实现
  8. Android ListView 知识点总结
  9. Android 收缩展开动画
  10. android launcher语言设置修改