前言
上篇簡單介紹了UniversalImageLoader的使用,分析了下原始碼,大致可以進行如下劃分,本文將分析圖片載入的Imageloader實現,。
本文
通過ImageLoader執行個體對象,調用public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener)發放將開始載入圖片,具體過程可以分為幾個階段:
合法性檢查
主要是初始化檢查和參數檢查,可能會拋出異常或是下載不受幹擾可以繼續;有傳入的圖片地址為空白,imageview為空白,圖片配置執行個體為空白,過程監聽介面為空白四種情況。
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; }
如果沒有初始化ImageLoader是比較嚴重的,將直接拋出運行時異常,控制項ImageView為空白時不影響,可以直接退出,不再下載,圖片配置和監聽介面為空白則將啟用預設值,至於圖片url的話,由於初始化時已經執行個體化了預設值的情形,所以將顯示本地設定的預設圖片,同時將控制項移出HashMap。
載入準備
這裡的準備操作一個是擷取圖片的尺寸參數,然後根據這個參數和url產生標記ImageView的key,最後以key-value的形式存入HashMap中備用,
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,如果不為空白且未被標記為回收狀態,那麼就可以使用這個緩衝的bitmap,調用監聽介面的onLoadingStarted()處理一些載入錢的操作,然後對bitmap做一些顯示前的操作,這個就用到傳入進來的圖片顯示的option配置,如果沒傳這個值,那啟用預設值,應該是不對bitmap操作,這個預設的option使用SimpleBitmapDisplayer 執行個體,查看其原始碼,果然,是直接將bitmap設定給ImageView然後對外返回原來的Bitmap,對於這種情況後面的在此設定bitmap給imageview其實有些累贅,重複操作了。
public final class SimpleBitmapDisplayer implements BitmapDisplayer { @Override public Bitmap display(Bitmap bitmap, ImageView imageView) { imageView.setImageBitmap(bitmap); return bitmap; } }
接下來調用監聽介面的onLoadingComlete();到顯示記憶體緩衝圖片的操作就結束了,下面介紹第二種情況,就是從磁碟緩衝/網新下載圖片。
先調用監聽介面的onLoadingStarted();接著顯示一個下載過程中的圖片或則乾脆在下載時不顯示任何圖片。接著檢查一下線程池是否初始化並正常工作中checkExecutors(),查看原始碼可以發現,項目用與下載的的task其實是通過ExecutorService來管理,如果還不知道什麼是ExecutorService趕緊去補一下java的多線程並發編程吧。
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); } }
為了下載圖片這裡把必要的圖片資訊做了一個封裝傳給背景工作執行緒。ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, options, listener, getLockForUri(uri));
現在一起看一下他的背景工作執行緒是怎麼寫的。LoadAndDisplayImageTask displayImageTask = new LoadAndDisplayImageTask(configuration, imageLoadingInfo, new Handler());
這裡的最後一個參數是我們熟悉的Handler 執行個體,可以預測這個task類應該是Runnale的是子類,在run()中根據情況向handler發送處理操作請求。(未完待續)