简单来说就是用于加载图片的一个开源项目,在其项目介绍中是这么写的
其他类似的项目也有很多,但这个作为github上著名的开源项目被广泛使用。第三方的包虽然好用省力,可以有效避免重复造轮子,但是却隐藏了一些开发上的细节,如果不关注其内部实现,那么将不利于掌握核心技术,当然也谈不上更好的使用它,计划分析项目的集成使用和低层实现。
源码地址:https://github.com/nostra13/Android-Universal-Image-Loader
这基本也就是几行代码,下面这张图里有实例化和初始化的过程。
关于这个实例化,是线程安全,忽略第二层判断,如果A,B线程同时执行if(instance==null),A,B都满足条件进入,此时,其中一个换锁,另一个等待,还需要再次判断instance==null(这是必要的,否则可能使得,再次实例化)这样一个单例就正常初始化了。
配置完后,就可以开始使用了,通过ImageLoader的displayImage()绑定一个图片和ImageView,该方法有四个重载版本,传的参数比较多,这也印证了该项目提供每个图片单独的显示配置这一说法。
其中参数最全的是:
displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener);
另外三个其实就是减少其中几个参数用默认的值而已。
比较重要的是后面两个,DisplayImageOptions options,图片的参数配置对象
options = new DisplayImageOptions.Builder() .showStubImage(R.drawable.stub_image) .showImageForEmptyUri(R.drawable.image_for_empty_url) .cacheInMemory() .cacheOnDisc() .build();
来看看都有什么信息可以配置的,
除此之外还有两个
最后一个参数ImageLoadingListener listener当然是监听过程的回调接口
图片加载的Imageloader实现
通过ImageLoader实例对象,调用public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener)发放将开始加载图片
具体过程可以分为几个阶段
主要是初始化检查和参数检查,可能会
if (configuration == null) { throw new RuntimeException(ERROR_NOT_INIT); } if (imageView == null) { Log.w(TAG, ERROR_WRONG_ARGUMENTS); return; } if (listener == null) { listener = emptyListener; } if (options == null) { options = configuration.defaultDisplayImageOptions; } if (uri == null || uri.length() == 0) { cacheKeyForImageView.remove(imageView); listener.onLoadingStarted(); if (options.isShowImageForEmptyUri()) { imageView.setImageResource(options.getImageForEmptyUri()); } else { imageView.setImageBitmap(null); } listener.onLoadingComplete(null); return; }
targetSize = getImageSizeScaleTo(imageView); String memoryCacheKey = MemoryCacheKeyUtil.generateKey(uri, targetSize); cacheKeyForImageView.put(imageView, memoryCacheKey);
加载分为调用内存缓存和本地缓存/网络下载,根据上一步加载准备中得到的key获取bitmap,这个过程比较发杂
先看看从内存缓存获取图片
if (bmp != null && !bmp.isRecycled()) { if (configuration.loggingEnabled) Log.i(TAG, String.format(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey)); listener.onLoadingStarted(); Bitmap displayedBitmap = options.getDisplayer().display(bmp, imageView); imageView.setImageBitmap(displayedBitmap); listener.onLoadingComplete(bmp); }
查看其源代码,果然是直接将bitmap设置给ImageView然后对外返回原来的Bitmap,对于这种情况后面的在此设置bitmap给imageview其实有些累赘,重复操作了。
public final class SimpleBitmapDisplayer implements BitmapDisplayer { @Override public Bitmap display(Bitmap bitmap, ImageView imageView) { imageView.setImageBitmap(bitmap); return bitmap; } }
下面介绍第二种情况,就是从磁盘缓存/网新下载图片。
查看源代码可以发现,项目用与下载的的task其实是通过ExecutorService来管理
private void checkExecutors() { if (imageLoadingExecutor == null || imageLoadingExecutor.isShutdown()) { imageLoadingExecutor = Executors.newFixedThreadPool(configuration.threadPoolSize, configuration.displayImageThreadFactory); } if (cachedImageLoadingExecutor == null || cachedImageLoadingExecutor.isShutdown()) { cachedImageLoadingExecutor = Executors.newFixedThreadPool(configuration.threadPoolSize, configuration.displayImageThreadFactory); } }
http://blog.csdn.net/wwj_748/article/details/10079311
https://github.com/nostra13/Android-Universal-Image-Loader
http://blog.csdn.net/wwj_748/article/details/10079311
http://www.cnblogs.com/avenwu/