今天写一下关于ImageLoader的文章,看下图:
最终会调用displayImage方法的源码是:
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) { this.checkConfiguration(); if(imageAware == null) { throw new IllegalArgumentException("Wrong arguments were passed to displayImage() method (ImageView reference must not be null)"); } else { if(listener == null) { listener = this.defaultListener; } if(options == null) { options = this.configuration.defaultDisplayImageOptions; } if(TextUtils.isEmpty(uri)) { this.engine.cancelDisplayTaskFor(imageAware); listener.onLoadingStarted(uri, imageAware.getWrappedView()); if(options.shouldShowImageForEmptyUri()) { imageAware.setImageDrawable(options.getImageForEmptyUri(this.configuration.resources)); } else { imageAware.setImageDrawable((Drawable)null); } listener.onLoadingComplete(uri, imageAware.getWrappedView(), (Bitmap)null); } else { ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, this.configuration.getMaxImageSize()); String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize); this.engine.prepareDisplayTaskFor(imageAware, memoryCacheKey); listener.onLoadingStarted(uri, imageAware.getWrappedView()); //这里先尝试从内存缓存(ImageLoader有内存,硬盘缓存)中取图片 Bitmap bmp = this.configuration.memoryCache.get(memoryCacheKey); ImageLoadingInfo imageLoadingInfo; //这里是拿到了图片 if(bmp != null && !bmp.isRecycled()) { L.d("Load image from memory cache [%s]", new Object[]{memoryCacheKey}); //判断图片需不需要处理,如果需要处理 if(options.shouldPostProcess()) { imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri)); //创建一个处理并显示的线程任务 并添加到 taskExecutorForCachedImages 线程池里面 ProcessAndDisplayImageTask displayTask1 = new ProcessAndDisplayImageTask(this.engine, bmp, imageLoadingInfo, defineHandler(options)); if(options.isSyncLoading()) { displayTask1.run(); } else { //添加到taskExecutorForCachedImages 线程池 this.engine.submit(displayTask1); } } else { //不需要处理就直接显示 options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE); listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp); } } else { if(options.shouldShowImageOnLoading()) { imageAware.setImageDrawable(options.getImageOnLoading(this.configuration.resources)); } else if(options.isResetViewBeforeLoading()) { imageAware.setImageDrawable((Drawable)null); } imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri)); //没有在内存中,那就创建一个下载并显示的线程任务,添加到 taskDistributor 线程任务中,这里需要注意的是这个是添加到分发线程池里面,不是直接去 //下载的 LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(this.engine, imageLoadingInfo, defineHandler(options)); if(options.isSyncLoading()) { displayTask.run(); } else { this.engine.submit(displayTask); } } } } } 现在看 this.engine.submit(displayTask) 函数(图片没有在内存中的,也就是上面红色的部分,内存中有的要么直接显示,要么直接添加到taskExecutorForCachedImages里面,不需要分发)的源码:void submit(final LoadAndDisplayImageTask task) { //没有直接去下载,而是先根据情况分发事件 this.taskDistributor.execute(new Runnable() { public void run() { File image = ImageLoaderEngine.this.configuration.diskCache.get(task.getLoadingUri()); boolean isImageCachedOnDisk = image != null && image.exists(); ImageLoaderEngine.this.initExecutorsIfNeed(); //这里是在硬盘缓存中存在的图片,直接添加到 taskExecutorForCachedImages 线程池,也是属于从缓存中取的,那为什么没有直接取出来而要另起线程呢? //那是因为硬盘读数据比内存读数据慢,所以放在线程里 if(isImageCachedOnDisk) { ImageLoaderEngine.this.taskExecutorForCachedImages.execute(task); } else { //因为硬盘上也没有,只能放在从网络下载的线程池里面 ImageLoaderEngine.this.taskExecutor.execute(task); } } }); } submit函数中不管是放在那个线程池中,都会执行 LoadAndDisplayImageTask 的 run 函数,至于为什么分线程池呢?可能是想更好的利用系统资源吧,这个以后再研究, 如果有不对的地方还请高手给我指点,一起学习一起进步。