ImageView加载图片的几种方式学习

2,546 阅读2分钟

ImageView加载图片的几种方式

加载方式

setImageResource(int res)

源码

setImageURI(int res)

源码

setImageBitmap(int res)

源码

setImageDrawable(Drawable)

源码
其中setImageResource和setImageURI都会走updateDrawable(null) ,mResource和mUri再分别赋值,最后都会走resolveUri(); 而setImageDrawable就会直接调用updateDrawable(drawable);

在resolveUri中

private void resolveUri() {
    if (mDrawable != null) {
        return;
    }

    if (getResources() == null) {
        return;
    }

    Drawable d = null;

    if (mResource != 0) {
        try {
            d = mContext.getDrawable(mResource);
        } catch (Exception e) {
            Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
            // Don't try again.
            mResource = 0;
        }
    } else if (mUri != null) {
        d = getDrawableFromUri(mUri);

        if (d == null) {
            Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri);
            // Don't try again.
            mUri = null;
        }
    } else {
        return;
    }

    updateDrawable(d);
}

如果mResource!=0 --> mContext.getDrawable(mResource) 如果mUri != null --> getDrawableFromUri

getDrawableFromUri中的流程
将图片转为了文件流,然后把文件流解析为Bitmap,最后包装成Drawable,然后 updateDrawable(drawable); 还有一种android:src方式:
src
其实调用的也是 setImageDrawable

通过上面的分析,可以知道

  • setImageURI的方式,流程中多了几步,可能存在延时;
  • setImageDrawable是流程比较少的设置方式;
  • 所以,不管是setImageUri还是setImageDrawable或者setImageResource()或者setImageBitmap 都会把传递过来的对象通过resolveUri转换成一个Drawable对象,然后updateDrawable,最后invalidate绘制。

updateDrawable 在流程中这是一个重要的方法

 private void updateDrawable(Drawable d) {
    if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
        mRecycleableBitmapDrawable.setBitmap(null);
    }

    boolean sameDrawable = false;

    if (mDrawable != null) {
        sameDrawable = mDrawable == d;
        mDrawable.setCallback(null);
        unscheduleDrawable(mDrawable);
        if (!sCompatDrawableVisibilityDispatch && !sameDrawable && isAttachedToWindow()) {
            mDrawable.setVisible(false, false);
        }
    }

    mDrawable = d;

    if (d != null) {
        d.setCallback(this);
        d.setLayoutDirection(getLayoutDirection());
        if (d.isStateful()) {
            d.setState(getDrawableState());
        }
        if (!sameDrawable || sCompatDrawableVisibilityDispatch) {
            final boolean visible = sCompatDrawableVisibilityDispatch
                    ? getVisibility() == VISIBLE
                    : isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
            d.setVisible(visible, true);
        }
        d.setLevel(mLevel);
        mDrawableWidth = d.getIntrinsicWidth();
        mDrawableHeight = d.getIntrinsicHeight();
        applyImageTint();
        applyColorMod();
		
        configureBounds();
    } else {
        mDrawableWidth = mDrawableHeight = -1;
    }
}

在mDrawable不为空的时候; 有几个方法比较重要;

1.applyImageTint:应用图片的着色模式

可以通过setImageTintMode来指定用于应用由指定的色调的混合模式 ColorStateList是模式的集合,在不设置的情况下,默认是SRC_IN(取两层绘制交集中的源图像。),总共有16中模式

2.applyColorMod//设置图片的颜色过滤

private void applyColorMod() {
    if (mDrawable != null && mColorMod) {
        mDrawable = mDrawable.mutate();
        if (mHasColorFilter) {
            mDrawable.setColorFilter(mColorFilter);
        }
        mDrawable.setXfermode(mXfermode);
        mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
    }
}

mColorFilter是过滤器变量,只有在发生修改时才进行变异和应用。这应该不重置mColorMod标志,因为这些过滤器需要如果更改了可拉伸部分,则重新应用。

setColorFilter

3.configureBounds()方法配置边界

  • 如果drawable没有内在尺寸,或者被告知缩放到合适的大小,然后就会填充整个视图;
  • 否则。需要自己缩放,使用其本机大小;
  • ScaleType的相关设置
  • 最后就是在ondraw()方法中将mDrawable绘制出来。

ImageVIew设置图片的大概流程,还处于初步看源码学习,细节上没有深入,有不对之处,还望指出。