开源图片加载框架——Universal-Image-Loader学习

介绍

先来看下它的特性:

可配置度高。支持任务线程池、下载器、解码器、内存及磁盘缓存、显示选项等等的配置。

包含内存缓存和磁盘缓存两级缓存。

支持多线程,支持异步和同步加载。

支持多种缓存算法、下载进度监听、ListView 图片错乱解决等。

使用

首先需要在Application里面配置它的相关参数并初始化,当然你也可以不用配置直接使用默认配置:

public class MyApplication extends Application {  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
  
        //创建默认的ImageLoader配置参数  
        ImageLoaderConfiguration configuration = ImageLoaderConfiguration  
                .createDefault(this);  
          
        //使用自定义的参数 
        ImageLoader.getInstance().init(configuration);  
    }  
  
}  
File cacheDir = StorageUtils.getCacheDirectory(context);  
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)  
        .memoryCacheExtraOptions(480, 800) // default = device screen dimensions  
        .diskCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null)  
        .taskExecutor(...)  
        .taskExecutorForCachedImages(...)  
        .threadPoolSize(3) // default  
        .threadPriority(Thread.NORM_PRIORITY - 1) // default  
        .tasksProcessingOrder(QueueProcessingType.FIFO) // default  
        .denyCacheImageMultipleSizesInMemory()  
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))  
        .memoryCacheSize(2 * 1024 * 1024)  
        .memoryCacheSizePercentage(13) // default  
        .diskCache(new UnlimitedDiscCache(cacheDir)) // default  
        .diskCacheSize(50 * 1024 * 1024)  
        .diskCacheFileCount(100)  
        .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default  
        .imageDownloader(new BaseImageDownloader(context)) // default  
        .imageDecoder(new BaseImageDecoder()) // default  
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default  
        .writeDebugLogs()  
        .build();

 参数配置里面有很多的可配置项,比如缓存策略、加载线程池大小等,可以根据自己需求配置,这里就不一一讲解了,我们来看下调用方法,框架给我们提供了不止一种的方法来实现加载图片,下面我们来看下几个常用的方法:

loadImage()

final ImageView mImageView = (ImageView) findViewById(R.id.image);  
        String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";  
          
        ImageLoader.getInstance().loadImage(imageUrl, new ImageLoadingListener() {  
              
            @Override  
            public void onLoadingStarted(String imageUri, View view) {  
                  
            }  
              
            @Override  
            public void onLoadingFailed(String imageUri, View view,  
                    FailReason failReason) {  
                  
            }  
              
            @Override  
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {  
                mImageView.setImageBitmap(loadedImage);  
            }  
              
            @Override  
            public void onLoadingCancelled(String imageUri, View view) {  
                  
            }  
        });

该方法有两个参数,一个是url,一个是ImageLoadingListener,ImageLoadingListener回调方法有4个,图片加载开始,图片加载失败,图片加载完成,图片取消加载,我们可以根据自己的需要在对应的方法写自己的代码。当然如果你不需要这个么多方法,只需要加载完成显示,那可以传一个SimpleImageLoadingListener,他使用的是缺省适配器模式,只需要一个onLoadingComplete方法。

final ImageView mImageView = (ImageView) findViewById(R.id.image);  
        String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";  
          
        ImageLoader.getInstance().loadImage(imageUrl, new SimpleImageLoadingListener(){  
  
            @Override  
            public void onLoadingComplete(String imageUri, View view,  
                    Bitmap loadedImage) {  
                super.onLoadingComplete(imageUri, view, loadedImage);  
                mImageView.setImageBitmap(loadedImage);  
            }  
              
        });

loadImage还有一个重载方法,可以自定义图片的大小,我们需要自己实例化一个ImageSize对象,设定图片大小传入即可。

final ImageView mImageView = (ImageView) findViewById(R.id.image);  
        String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";  
          
        ImageSize mImageSize = new ImageSize(100, 100);  
          
        ImageLoader.getInstance().loadImage(imageUrl, mImageSize, new SimpleImageLoadingListener(){  
  
            @Override  
            public void onLoadingComplete(String imageUri, View view,  
                    Bitmap loadedImage) {  
                super.onLoadingComplete(imageUri, view, loadedImage);  
                mImageView.setImageBitmap(loadedImage);  
            }  
              
        });

上面是比较简单的用法,我们平时一般需要更复杂的用法。loadImage还有一个重载方法来满足我们的需求,我们可以传入一个DisplayImageOptions来配置一些复杂的参数,比如图片加载之前显示的默认图片,加载失败显示的图片,是否缓存等。

DisplayImageOptions options = new DisplayImageOptions.Builder()  
        .showImageOnLoading(R.drawable.ic_stub) // resource or drawable  
        .showImageForEmptyUri(R.drawable.ic_empty) // resource or drawable  
        .showImageOnFail(R.drawable.ic_error) // resource or drawable  
        .resetViewBeforeLoading(false)  // default  
        .delayBeforeLoading(1000)  
        .cacheInMemory(false) // default  
        .cacheOnDisk(false) // default  
        .preProcessor(...)  
        .postProcessor(...)  
        .extraForDownloader(...)  
        .considerExifParams(false) // default  
        .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default  
        .bitmapConfig(Bitmap.Config.ARGB_8888) // default  
        .decodingOptions(...)  
        .displayer(new SimpleBitmapDisplayer()) // default  
        .handler(new Handler()) // default  
        .build();

他的用法跟前面的用法一样,直接作为一个参数传入即可,这里就不再贴代码了。

displayImage()

final ImageView mImageView = (ImageView) findViewById(R.id.image);  
        String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";  
          
        //显示图片的配置  
        DisplayImageOptions options = new DisplayImageOptions.Builder()  
                .showImageOnLoading(R.drawable.ic_stub)  
                .showImageOnFail(R.drawable.ic_error)  
                .cacheInMemory(true)  
                .cacheOnDisk(true)  
                .bitmapConfig(Bitmap.Config.RGB_565)  
                .build();  
          
        ImageLoader.getInstance().displayImage(imageUrl, mImageView, options);

通过代码可以看到,displayImage方法要简单一点,不需要传入Listener接口,只需要传入url,imageview控件,options即可。这个方法内部会对我们要显示的图片进行剪裁,返回给我们一个大小合适的图片。在图片加载过程中我们有时会需要图片加载的进度,displayImage可以传入一个ImageLoadingProgressListener()来给我们返回进度:

imageLoader.displayImage(imageUrl, mImageView, options, new SimpleImageLoadingListener(), new ImageLoadingProgressListener() {  
              
            @Override  
            public void onProgressUpdate(String imageUri, View view, int current,  
                    int total) {  
                  
            }  
        });

除了加载网络图片我们还可以加载本地图片或者是assets,drawable里面的图片,这样的话我们只需要改变一下url就可以的,比如加载本地图片我们首先要知道图片的路径,然后用Scheme.FILE.wrap(path)包装一下即可,相同的assets,drawable,调用Scheme.ASSETS.wrap(path);Scheme.DRAWABLE.wrap(path),看下这个方法的源码:

 /** Represents supported schemes(protocols) of URI. Provides convenient methods for work with schemes and URIs. */
 public enum Scheme {
  HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN("");
  private String scheme;
  private String uriPrefix;
  Scheme(String scheme) {
   this.scheme = scheme;
   uriPrefix = scheme + "://";
  }

其实包装以后的路径添加了对应的:file://。

我们知道在listview,gridview里面的图片加载是比较常用的,我们希望在listvew或girdview滑动的时候不加载图片,等我们停下时候再加载,框架也为我们提供了这样一个监听:

listView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));  
gridView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));

pauseOnScroll、pauseOnFling是boolean类型的,pauseOnScroll为true代表滑动的时候暂停加载,pauseOnFling为true代表猛的滑动过程停止加载。

缓存策略

框架在缓存处理上做得很到位,它的缓存分两种一种是内存缓存,一种是硬盘缓存,先来看下内存缓存。内存缓存用了LRU least recently used 近期最少使用 算法,也就是说如果缓存空间超过了我们设定的空间大小,那么框架会把近期最少用到的bitmap从缓存移除,存储的结构是基于链表结构的LinkedHashMap。当然自己也可以自定义缓存策略,在初始化配置的时候设置进去。

内存缓存用到了强引用缓存,弱引用缓存还有两者结合的缓存策略。强引用指的是如果创建了一个对象赋给了一个变量,那么这个对象永远不会被垃圾回收机制回收,及时OOM也不会回收,弱引用的对象就会被回收了。

我们来看一下强引用的LruMemoryCache,这个缓存类内部维护的是一个LinkedHashMap,我们为缓存的最大值设置了一个maxsize,缓存图片的时候我们会计算没个图片的大小,根据key判断如果已经缓存了这张照片,那么就把以前的照片移除;如果当前缓存的大小小于maxsize,则不作操作;如果大于maxsize则把第一条数据移除。

硬盘缓存有这样几个类型:

  • FileCountLimitedDiscCache(可以设定缓存图片的个数,当超过设定值,删除掉最先加入到硬盘的文件)

  • LimitedAgeDiscCache(设定文件存活的最长时间,当超过这个值,就删除该文件)

  • TotalSizeLimitedDiscCache(设定缓存bitmap的最大值,当超过这个值,删除最先加入到硬盘的文件)

  • UnlimitedDiscCache(这个缓存类没有任何的限制)

如果上面的几个不符合你的项目需求也可以自定义配置。

 

 

关于ImageLoader的学习就到这里,有时间的话看一下源码,可能会有意想不到的收获。

 

 

 

 

你可能感兴趣的:(图片异步加载,ImageLoader)