image派
setImageBitmapsetImageDrawablesetImageResourcesetImageURIupdateDrawable和resolveUri
updateDrawableresolveUri background 派
setBackgroundResourcesetBackgroundsetBackgroundDrawableImageview的属性 background和src的区别 总结
我们知道,对于Imageview显示图片,常用的有一下几种方式
imaegView.setImageBitmap();
imaegView.setImageResource();
imaegView.setImageDrawable();
imaegView.setImageURI();
imaegView.setBackground();
imaegView.setBackgroundResource();
imaegView.setBackgroundDrawable();
一般常用的应该就是这几种了,可是这几种有什么区别呢,由以上方法咱们可以分为两个派系,以setImage开头的image派和以setBackground开头的background派,下面分别从源码角度查看分析这两个派系
image派
setImageBitmap()
public void setImageBitmap(Bitmap bm) {
setImageDrawable(
new BitmapDrawable(mContext.getResources(), bm));
}
通过源码可知,setImageBitmap()最终是把传递过来的bitmap转换成一个Drawable对象,然后调用的setImageDrawable()方法,那setImageDrawable()方法又是干嘛的啊
setImageDrawable()
public void setImageDrawable(Drawable drawable) {
if (mDrawable != drawable) {
mResource =
0;
mUri =
null;
final int oldWidth = mDrawableWidth;
final int oldHeight = mDrawableHeight;
updateDrawable(drawable);
if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
requestLayout();
}
invalidate();
}
}
由源码可知, * 全局变量mResource设置为0, * 全局变量mUri置为null, * 把传递过来的drawable对象再传递到updateDrawable()法中
setImageResource()
public void setImageResource(
int resId) {
final int oldWidth = mDrawableWidth;
final int oldHeight = mDrawableHeight;
updateDrawable(
null);
mResource = resId;
mUri =
null;
resolveUri();
if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
requestLayout();
}
invalidate();
}
没有Drawable对象,所以 updateDrawable()传递null把传递过来的res对象赋值给 全局变量mResource,全局变量mUri置为null,调用 resolveUri()
setImageURI()
public void setImageURI(Uri uri) {
if (mResource !=
0 || (mUri != uri && (uri ==
null || mUri ==
null || !uri.equals(mUri)))) {
updateDrawable(
null);
mResource =
0;
mUri = uri;
final int oldWidth = mDrawableWidth;
final int oldHeight = mDrawableHeight;
resolveUri();
if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
requestLayout();
}
invalidate();
}
}
全局变量mResource设置为0把传递过来的uri对象赋值给全局变量mUri,由于没有Drawable对象,所以 updateDrawable()递null调用 resolveUri()
从上可知,有两个方法挺关键的,一个是updateDrawable(),还有就是resolveUri(),接下来就查查这两个方法是干嘛的
updateDrawable()和resolveUri()
updateDrawable()
private void updateDrawable(Drawable d) {
if (mDrawable !=
null) {
mDrawable.setCallback(
null);
unscheduleDrawable(mDrawable);
}
mDrawable = d;
if (d !=
null) {
d.setCallback(
this);
if (d.isStateful()) {
d.setState(getDrawableState());
}
d.setLevel(mLevel);
d.setLayoutDirection(getLayoutDirection());
d.setVisible(getVisibility() == VISIBLE,
true);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
applyColorMod();
configureBounds();
}
else {
mDrawableWidth = mDrawableHeight = -
1;
}
}
由于setImageURI()和setImageResource()递过来的d 为null,只是执行了else 中的语句,即把全局变量 mDrawableWidth = mDrawableHeight 设置为-1如果d不为null,就是对drawable的一些更新
resolveUri()
private void resolveUri() {
if (mDrawable !=
null) {
return;
}
Resources rsrc = getResources();
if (rsrc ==
null) {
return;
}
Drawable d =
null;
if (mResource !=
0) {
try {
d = rsrc.getDrawable(mResource);
}
catch (Exception e) {
mUri =
null;
}
}
else if (mUri !=
null) {
String scheme = mUri.getScheme();
if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
try {
ContentResolver.OpenResourceIdResult r = mContext.getContentResolver().getResourceId(mUri);
d = r.r.getDrawable(r.id);
}
catch (Exception e) {
Log.w(
"ImageView",
"Unable to open content: " + mUri, e);
}
}
else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
InputStream stream =
null;
try {
stream = mContext.getContentResolver().openInputStream(mUri);
d = Drawable.createFromStream(stream,
null);
}
catch (Exception e) {
Log.w(
"ImageView",
"Unable to open content: " + mUri, e);
}
finally {
if (stream !=
null) {
try {
stream.close();
}
catch (IOException e) {
Log.w(
"ImageView",
"Unable to close content: " + mUri, e);
}
}
}
}
else {
d = Drawable.createFromPath(mUri.toString());
}
if (d ==
null) {
System.out.println(
"resolveUri failed on bad bitmap uri: " + mUri);
mUri =
null;
}
}
else {
return;
}
updateDrawable(d);
}
通过上面的代码可知 * 如果mResource不为null ,把mResource 转换成一个Drawable对象,然后执行updateDrawable() * 如果mUri不为null,就把uri转换成一个Drawable对象,然后执行updataDrawable()方法
所以,不管是setImageUri还是setImageDrawable或者setImageResource()或者setImageBitmap * 首先都是把传递过来的对象转换成一个Drawable对象, * 然后把执行updataDrawable()方法, * 因为之前在updataDrawable 中重新设置的宽高,所以执行requestLayout() 重新布局view * 最后执行invalidate()重新绘制
background 派
然后我们发现,background派的方法都是来自与ImageView的父类View中的
setBackgroundResource()
public void setBackgroundResource(
int resid) {
if (resid !=
0 && resid == mBackgroundResource) {
return;
}
Drawable d =
null;
if (resid !=
0) {
d = mContext.getDrawable(resid);
}
setBackground(d);
mBackgroundResource = resid;
}
把传递过来的resid转换成一个Drawable对象,然后调用setBackground()
setBackground()
public void setBackground(Drawable background) {
setBackgroundDrawable(background);
}
调用setBackgroundDrawable方法
setBackgroundDrawable
/**
* @deprecated use {@link #setBackground(Drawable)} instead
*/
public void setBackgroundDrawable(Drawable background) {
computeOpaqueFlags();
if (background == mBackground) {
return;
}
boolean requestLayout =
false;
mBackgroundResource =
0;
if (mBackground !=
null) {
mBackground.setCallback(
null);
unscheduleDrawable(mBackground);
}
if (background !=
null) {
Rect padding = sThreadLocal.get();
if (padding ==
null) {
padding =
new Rect();
sThreadLocal.set(padding);
}
resetResolvedDrawables();
background.setLayoutDirection(getLayoutDirection());
if (background.getPadding(padding)) {
resetResolvedPadding();
switch (background.getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
mUserPaddingLeftInitial = padding.right;
mUserPaddingRightInitial = padding.left;
internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
break;
case LAYOUT_DIRECTION_LTR:
default:
mUserPaddingLeftInitial = padding.left;
mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
mLeftPaddingDefined =
false;
mRightPaddingDefined =
false;
}
if (mBackground ==
null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
mBackground.getMinimumWidth() != background.getMinimumWidth()) {
requestLayout =
true;
}
background.setCallback(
this);
if (background.isStateful()) {
background.setState(getDrawableState());
}
background.setVisible(getVisibility() == VISIBLE,
false);
mBackground = background;
if ((mPrivateFlags & PFLAG_SKIP_DRAW) !=
0) {
mPrivateFlags &= ~PFLAG_SKIP_DRAW;
mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
requestLayout =
true;
}
}
else {
mBackground =
null;
if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) !=
0) {
mPrivateFlags &= ~PFLAG_ONLY_DRAWS_BACKGROUND;
mPrivateFlags |= PFLAG_SKIP_DRAW;
}
requestLayout =
true;
}
computeOpaqueFlags();
if (requestLayout) {
requestLayout();
}
mBackgroundSizeChanged =
true;
invalidate(
true);
}
注意该方法的注释@deprecated 说明已经过时了,让使用setBackground()方法,可是我就不明白了,setBackground方法里面是直接调用的setBackgroundDrawable()方法,不知道为啥这样设计,可能Google工程师为了简化方法名称吧。 setBackgroundDrawable()最后也会执行到requestLayout()和invalidate(true)方法,
其实这几个方法的区别最终归结到就是 setBackgroundDrawable(drawable)和setImageDrawable(Drawable)的区别 其实这两个的区别又让我想起了Image属性中的background和src的区别,这又有什么关系呢,然后继续查找代码,在ImageView中的构造函数中找到了答案 然后在View中找关于backgroud属性的一些。
switch (attr) {
case com.android.internal.R.styleable.View_background:
background = a.getDrawable(attr);
...
}
....
if (background !=
null) {
setBackground(background);
}
于是就得到了下面的结论: * android:background=”“相当于执行setBackgroundDrawable() * android:src=”“相当于执行setBackgroundDrawable()
关于这两个的区别,可以参考这篇blog setBackgroundDrawable与setImageDrawable的区别
至于background和src的其他的区别,参考网上得知
Imageview的属性 background和src的区别
src是图片内容(前景),bg是背景,可以同时使用。 background会根据ImageView组件给定的长宽进行拉伸,而src就存放的是原图的大小,不会进行拉伸 。scaleType只对src起作用;bg可设置透明度。
总结
稍微总结一下,就是关于ImageView 显示图片的几种方式,
imaegView.setImageBitmap();
imaegView.setImageResource();
imaegView.setImageDrawable();
imaegView.setImageURI();
imaegView.setBackground();
imaegView.setBackgroundResource();
imaegView.setBackgroundDrawable();
主要都是在这两个方法中setBackgroundDrawable(drawable)和setImageDrawable(Drawable),而 android:background=”“相当于执行setBackgroundDrawable() android:src=”“相当于执行setBackgroundDrawable() 仅此而已,其实最主要 的分析还没有做,就是requestLayout()和invalidate()这两个方法,这两个是关于View的绘制的,以后会做相应的分析。