Android - ImageView:setImageBitmap与setImageDrawable的区别

42

setImageBitmapsetImageDrawable有什么区别?我想根据文件动态设置图像。我按照教程将我的Bitmap转换为BitmapDrawable,然后使用setImageDrawable进行设置。我发现直接使用setImageBitmap也可以工作,但是我没有注意到任何区别。

Bitmap image = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
BitmapDrawable bitmapDrawable = new BitmapDrawable(image);
imageView.setImageDrawable(bitmapDrawable);

或者

Bitmap image = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
imageView.setImageBitmap(image);

我认为这两个具体的例子没有区别。 - Eugen Martynov
5个回答

81

从内部来看,setImageBitmap 实际上在调用 setImageDrawable 方法,两者没有区别。

以下代码摘自 AOSP 的 ImageView.java 文件:

public void setImageBitmap(Bitmap bm) {
    // if this is used frequently, may handle bitmaps explicitly
    // to reduce the intermediate drawable object
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}

24
+1 是对查看 Android 源代码的支持。这是开源软件的一个好处。 - Jochem
2
新 BitmapDrawable(Resource, Bitmap) 和已弃用的构造函数 new BitmapDrawable(Bitmap) 之间的区别在于,如果您使用已弃用的构造函数,则可能会出现布局问题。 - Informatic0re
19
我不同意这个结论。事实上,如果您想要优化具有图像的列表视图,最好在UI线程之外创建一个Drawable,并将其分配给UI线程中的每个ImageView。如果使用Bitmap,则Drawable的创建将使UI线程变慢,从而导致列表无法快速且平滑地滚动。 - Snicolas

18

实际上,如果你有时将null用作参数,则可能会看到差异:

imageView.setImageDrawable(null);
Drawable d = imageView.getDrawable(); // d == null

imageView.setImageBitmap(null);
Drawable d = imageView.getDrawable(); // d == some BitmapDrawable, != null

如果你正在检查 ImageView 中的 drawable 是否存在,请注意。


1
这是最重要的区别,谢谢您指出。我喜欢使用ImageView的逻辑来检查它是否已设置,所以这很好用。 - AutoM8R

14

我刚刚为此写了一篇文章。希望能够回答您的问题。

https://plus.google.com/112740367348600290235/posts/VNAfFLDcKrw

ImageView 有 4 个 API 可以用来指定图像。哪一个应该使用?它们之间有什么区别?

  1. setImageDrawable(Drawable drawable)
  2. setImageBitmap(Bitmap bm)
  3. setImageResource(int resId)
  4. setImageURI(URI uri)

通过名称,可以知道 ImageView 用于显示图像。但是什么是图像? Bitmap 是一个图像,这不难理解,我们使用 setImageBitmap 来实现。然而,在内部,ImageView 拥有一个 Drawable 而不是 Bitmap,这就是 setImageDrawable 的作用。当您调用 setImageBitmap 时,内部会首先将位图包装到 BitmapDrawable 中,它是一个 Drawable,然后再调用 setImageDrawable

以下是代码:

public void setImageBitmap(Bitmap bm) {
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}

那么,第三个和第四个API怎么样呢?

您应该已经知道有很多种方法可以创建位图:从文件路径、输入流、Uri或资源文件中创建。

BitmapFactory.decodeFile(String pathName)
BitmapFactory.decodeStream(Inputstream)
BitmapFactory.decodeResource(Resource res, int id)
BitmapFactory.decodeByteArray(byte[] data)

了解这一点后,就容易理解setImageResource/setImageUrisetImageBitmap是完全相同的。

总之,setImageDrawable是其他API所依赖的原始函数。另外三个函数只是帮助你少写代码的辅助方法。

此外,要牢记的是ImageView实际上拥有一个Drawable,它不一定是BitmapDrawable!您可以将任何Drawable设置为图像视图。

除了通过Java API设置Drawable之外,您还可以使用XML属性来设置ImageView的源Drawable。请参见下面的示例。请注意,形状可以是图像文件(.png、.jpg、.bmp)或XML文件。


但哪个API调用更快?setImageDrawable似乎是最快的,但其他的呢? - winklerrr

4
两种方法都是有效的,并且实现的结果相同。 在第一种方法中,您将位图包装在可绘制对象中,该对象是可在视图中绘制的任何内容的抽象表示。
可绘制对象的特殊之处在于,它们使您能够对其所包装的图形对象执行各种操作(缩放、平移、不透明度等)。
位图是可绘制的一种类型,您可以在此处了解更多有关可绘制的信息: http://developer.android.com/guide/topics/resources/drawable-resource.html 在第二种方法中,您直接访问位图位,而不涉及任何可绘制相关的操作,并将位图按原样绘制在视图上。
希望这可以帮助您,祝好,Max。

那么,对图像执行操作是将其转换为可绘制对象的唯一优势/区别吗?我接受了nandeesh的答案,因为它更适用于我的使用情况。 - meeeee
是的,本质上这就是位图可绘制对象的优势或应用。 - Max Raskin

0
public void setImageBitmap(Bitmap bm) {
// if this is used frequently, may handle bitmaps explicitly
// to reduce the intermediate drawable object
setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}

或许差别在于 mContext.getResources(),通过 mContext.getResources() 可以获取设备的像素密度,因此在屏幕上显示的效果也会不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接