UniversalImageLoader源码解读01-用来显示图片的ImageAware

来源:互联网 发布:js条件公式编辑器 编辑:程序博客网 时间:2024/05/18 02:09

    Android平台下有一个著名的图片加载框架叫UniversalImageLoader,这个框架经过几次重构才有今天,有良好的扩展性。如果你曾经在ListView中加载图片出现过图片错乱,如果你曾经因加载图片过多而遇到OOM,那么你应该考虑使用UniversalImageLoader了。


    UniversalImageLoader支持二级缓存,内存+磁盘缓存,图片一旦从网络下载后会保存在磁盘缓存里并缓存到内存,这样下次就不会去网络上重新下载,并且内存中如果存在就不会去磁盘上加载,在有限的内存设备上,这种方法增加了内存的换入换出操作,但是总的来说比烦人的OOM要好得多。


    本人使用的版本 Version name 1.9.4 Version code 39

    为了能够看懂UniversalImageLoader的源码,以下内容你必须知道怎么回事,否则读源码会有困难。本文假定读者有基本的Android控件编程能力。

    1) Java多线程的 Executor, 以及ExecutorService, WeakReference如何使用(网上自己去查)

    2) 如何使用 UniversalImageLoader(Sample code里有)


    解读源码是一件很痛苦的事,因为有时候我们明明知道整个项目是如何工作的,结构如何等等,但是真要是说明白却不知道从哪里下手,在此本人试图说清,欢迎拍砖

    下面从包的级别开始,从外层到最核心的代码

    com.nostra13.universalimageloader.core.imageaware 封装了图片组件,它将使用图片的控件抽象成 ImageAware,

ViewAware实现了ImageAware接口, ImageViewAware继承ViewAware, NonViewAware也实现了ImageAware接口  ViewAware的接口定义如下:


/* 理解UniversalImageLoader最好的方式就是先去搞清楚如何使用,然后去看每个包下面的接口,   因为UIL充分利用了接口进行抽象,封装了变化,实现了很好的可扩展性。为了方便说明,这里假定是ImageView的一个抽象,定义非常简单*/public interface ImageAware {int getWidth(); //获取ImageView的宽度int getHeight(); //获取ImageView的高度ViewScaleType getScaleType();//获取ImageView的缩放类型View getWrappedView();// 这个就是组件包装的View,通常是个ImageView,当然也可以是其他的Viewboolean isCollected();// 判断View是否被回收,后面会解释int getId();boolean setImageDrawable(Drawable drawable);// 给包装的View设置图片boolean setImageBitmap(Bitmap bitmap);} // 给包装的View设置图片



 /* 这个抽象类实现了大部分方法,而把设置图片的工作留给子类*/

public abstract class ViewAware implements ImageAware {public static final String WARN_CANT_SET_DRAWABLE = "Can't set a drawable into view. You should call ImageLoader on UI thread for it.";public static final String WARN_CANT_SET_BITMAP = "Can't set a bitmap into view. You should call ImageLoader on UI thread for it.";protected Reference<View> viewRef;//这就是为什么isCollected方法的由来protected boolean checkActualViewSize;public ViewAware(View view) {this(view, true);}public ViewAware(View view, boolean checkActualViewSize) {if (view == null) throw new IllegalArgumentException("view must not be null");this.viewRef = new WeakReference<View>(view);//采用弱引用包装,这样做会为Bitmap的缓存提供方便,如果被回收了,那么Bitmap或许没必要缓存了this.checkActualViewSize = checkActualViewSize;//尽量获取实际的View宽高,是尽量,如果获取不到,那就取布局参数的宽高}@Overridepublic int getWidth() {View view = viewRef.get();if (view != null) {final ViewGroup.LayoutParams params = view.getLayoutParams();int width = 0;if (checkActualViewSize && params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {width = view.getWidth(); // Get actual image width}if (width <= 0 && params != null) width = params.width; // Get layout width parameterreturn width;}return 0;}@Overridepublic int getHeight() {View view = viewRef.get();if (view != null) {final ViewGroup.LayoutParams params = view.getLayoutParams();int height = 0;if (checkActualViewSize && params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {height = view.getHeight(); // Get actual image height}if (height <= 0 && params != null) height = params.height; // Get layout height parameterreturn height;}return 0;}@Overridepublic ViewScaleType getScaleType() {return ViewScaleType.CROP;}@Overridepublic View getWrappedView() {return viewRef.get();// 可能为null}@Overridepublic boolean isCollected() {return viewRef.get() == null;}@Overridepublic int getId() {View view = viewRef.get();return view == null ? super.hashCode() : view.hashCode();}@Overridepublic boolean setImageDrawable(Drawable drawable) {if (Looper.myLooper() == Looper.getMainLooper()) {View view = viewRef.get();if (view != null) {setImageDrawableInto(drawable, view);return true;}} else {L.w(WARN_CANT_SET_DRAWABLE);}return false;}@Overridepublic boolean setImageBitmap(Bitmap bitmap) {if (Looper.myLooper() == Looper.getMainLooper()) {View view = viewRef.get();if (view != null) {setImageBitmapInto(bitmap, view);return true;}} else {L.w(WARN_CANT_SET_BITMAP);}return false;}protected abstract void setImageDrawableInto(Drawable drawable, View view);protected abstract void setImageBitmapInto(Bitmap bitmap, View view);}



0 0