整個庫結構大體可以分為:ImageLoaderEngine,Cache,ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor五大模塊
簡單來說,UIL工作原理就是ImageLoader收到加載及顯示圖片的任務,并將它交給ImageLoaderEngine,ImageLoaderEngine分發任務到具體線程池去執行,任務通過Cache和ImageDownloader獲取圖片,中間可能經過BitmapProcessor和ImageDecoder處理,最終轉換為Bitmap交給BitmapDisplayer在ImageAwar中顯示
整體設計和包結構
面向接口編程,每個模塊功能都有一個接口,都要一個BaseXXX基類,ImageAware是自定義控件,類似ImageView,是弱引用,當內存不足的時候會回收,釋放內存
ImageLoader.getInstance():懶漢式獲取單一的實例對象
ImageLoaderConfiguration自定義配置信息參數,有很多屬性可以設置,運用了封裝的思想
主要方法
getInstance()懶漢單利,雙層非空判斷,提高性能
init(config);初始化配置參數,參數configuration為ImageLoader的配置信息,包括圖片最大尺寸、任務線程池、磁盤緩存、下載器、解碼器,調用該方法會初始化ImageLoaderEngine屬性,該屬性為任務分發器
DisplayImage()加載并顯示圖片或夾雜并執行回調接口,ImageLoader加載圖片主要分為三類接口:displayImage()異步加載并顯示圖片到對應的ImageAware上,loadImage()表示異步加載圖片并執行回調接口,loadImageSync()表示同步加載圖片,這三類接口最后都會調用到這個函數進行圖片加載
Builder模式
用于構造函數繁多的ImageLoaderConfiguration,其屬性與ImageLoaderConfiguration類似,函數多事屬性設置函數
其主要函數和含義:
(1)build()按配置生成ImageLoaderConfiguration
(2)initEmptyFieldsWithDefaultValues():初始化值為null的屬性,若用戶沒有配置相關項,UIL會通過調用DefaultConfigurationFactory中的函數返回一個默認值當配置,downloader默認值為BaseImageDownloader.decoder默認值為BaseImageDecoder
(3)diskCacheSize(int maxCacheSize)設置磁盤緩存的最大字節數,如果大于0或者maxFileCount大于0,默認DiskCache會用LruDiskCache,否則使用無大小限制的UnlimitedDiskCache
(4)diskCacheFileCount(int maxFileCount)設置磁盤緩存文件夾下最大文件數,如果大于0或maxCacheSize大于0,DiskCache會用LruDiskCache,否則使用無大小限制的UnlimitedDiskCache
概念簡介:
1.ImageLoaderEngine:任務分發器,負責分發LoadAndDisplayImageTask和ProcessAndDisplayImageTask給具體
的線程池去執行
2.ImageAware:顯示圖片的對象
3.ImageDownloader:圖片下載器,負責從圖片的各個來源獲取輸入流
4.Cache:圖片緩存,分為MemoryCache和DiskCache兩部分
MemoryCache:內存圖片緩存,可向內存緩存中保存圖片或從內存緩存中讀取圖片
DiskCache:本地圖片緩存,可向本地磁盤緩存保存圖片或從本地磁盤讀取圖片
5.ImageDecoder:圖片解碼器,負責將輸入流ImputStream轉換為Bitmap對象
6.BitmapProcessor:圖片處理器,負責從緩存讀取或寫入前對圖片進行處理
7.BitmapDisplayer:將Bitmap對象顯示在響應的控件ImageAware上
8.LoadAndDisplayImageTask:用于加載并顯示圖片的任務
9.ProcessAndDisplayImageTask:用于處理并顯示圖片的任務
10.DisplayBitmapTask:用于顯示圖片的任務
ImageLoader.getWInstance();懶漢式獲取單一實例對象
ImageLoaderConfiguration自定義配置信息類中有許多自定義屬性克選擇,運用了封裝的思想
主要屬性:
(1). Resources resources
程序本地資源訪問器,用于加載DisplayImageOptions
中設置的一些 App 中圖片資源。
(2). int maxImageWidthForMemoryCache
內存緩存的圖片最大寬度。
(3). int maxImageHeightForMemoryCache
內存緩存的圖片最大高度。
(4). int maxImageWidthForDiskCache
磁盤緩存的圖片最大寬度。
(5). int maxImageHeightForDiskCache
磁盤緩存的圖片最大高度。
(6). BitmapProcessor processorForDiskCache
圖片處理器,用于處理從磁盤緩存中讀取到的圖片。
(7). Executor taskExecutor
ImageLoaderEngine
中用于執行從源獲取圖片任務的 Executor。
(8). Executor taskExecutorForCachedImages
ImageLoaderEngine
中用于執行從緩存獲取圖片任務的 Executor。
(9). boolean customExecutor
用戶是否自定義了上面的 taskExecutor。
(10). boolean customExecutorForCachedImages
用戶是否自定義了上面的 taskExecutorForCachedImages。
(11). int threadPoolSize
上面兩個默認線程池的核心池大小,即最大并發數。
(12). int threadPriority
上面兩個默認線程池的線程優先級。
(13). QueueProcessingType tasksProcessingType
上面兩個默認線程池的線程隊列類型。目前只有 FIFO, LIFO 兩種可供選擇。
(14). MemoryCache memoryCache
圖片內存緩存。
(15). DiskCache diskCache
圖片磁盤緩存,一般放在 SD 卡。
(16). ImageDownloader downloader
圖片下載器。
(17). ImageDecoder decoder
圖片解碼器,內部可使用我們常用的BitmapFactory.decode(…)
將圖片資源解碼成Bitmap
對象。
(18). DisplayImageOptions defaultDisplayImageOptions
圖片顯示的配置項。比如加載前、加載中、加載失敗應該顯示的占位圖片,圖片是否需要在磁盤緩存,是否需要在內存緩存等。
(19). ImageDownloader networkDeniedDownloader
不允許訪問網絡的圖片下載器。
(20). ImageDownloader slowNetworkDownloader
慢網絡情況下的圖片下載器。
內存緩存
在displayImage展示圖片的方法之前必須調用imageLoader.init(config)方法,否則會報錯,displayImage經過都次方法調用(方法必須具有單一原則,功能單一,一個方法只做一個事情),如果uri為空,顯示默認圖片,uri不為空,從內存中獲取Bitmap對象,如果uri為空,顯示默認圖片,如果uri不為空,從內存中獲取Bitmap對象,如果緩存中Bitmap對象不是空,且沒有被回收,則去內存緩存中加載圖片:判斷圖片是否有樣式,(在代碼中,將不同的圖片形狀策略封裝成對象傳遞,加載不同的樣式,為策略模式(代替if分支))。
如果設置有樣式,同步加載(Handler+Thread是同步機制)內存中的圖片或者交給線程池(Handler機制),異步加載內存中的圖片。
如果設置沒有樣式,默認使用SimpleBitmapDisplayer
磁盤緩存
如果緩存中Bitmap對象為空則從磁盤緩存或網絡中加載圖片。
通過LoadAndDisplayImageTask線程加載圖片,繼續判斷內存中是否有圖片對象,有就從內存中獲取,內存中沒有緩存的圖片,調用tryLoadBitmap()方法(嘗試從磁盤或網絡加載圖片),返回Bitmap對象,該方法先判斷磁盤中是否有圖片對象,如果有,通過decodeImage()方法從流中解碼位圖,用BitmapFactory.decodeStream()方法解碼流,然后將圖片緩存到內存中。顯示圖片,同步顯示(run()方法),異步顯示(線程池)
網絡緩存
如果沒有,從網絡加載圖片,其實就是調用HttpURLConnection去訪問網絡,獲取流后,默認使用LruDiskCache緩存到磁盤文件中,從磁盤中加載圖片,解碼成Bitmap對象,繼續磁盤緩存的分支
函數流程圖如下:
緩存機制的研究
內存緩存
通過ActivityManager獲取的getMemoryClass()方法獲取App最大可用內存大小,內存緩存最大字節數為App最大可用內存的1/8,默認采用最近最少使用方法,該方法在緩存滿時,優先刪除最近最少使用的元素,通過LinkedHashMap作為緩存池,創建LinkedHashMap對象的時候需要傳入三個參數,第三個參數表示是否需要根據訪問順序排序,true表示需要排序,最近訪問和最近加入的一樣放到最后面,false表示根據插入順序排序,如果為true,且緩存滿時,始終刪除第一個元素,即刪除最近最少使用的元素
磁盤緩存
如果在ImageLoaderConfiguration中配置了diskCacheSize和diskCacheFileCount就使用的是LruDiscCache,在緩存滿時,優先刪除最近最少使用的元素,通過緩存目錄下名為journal文件記錄緩存的所有操作,基于食物操作,UIL默認磁盤緩存目錄在sdcard/Android/data/包名/cache/uil-images/目錄中
如果沒有配置磁盤緩存的大小,默認使用沒有限制的磁盤緩存UnlimitedDiskCache();
** LoadAndDisplayImageTask**
加載并顯示圖片的Task,實現了Runnable接口,用于從網絡、文件系統或內存獲取圖片并解析,然后調用DisplayBitmapTask在ImageAware中顯示圖片
雜談LRU
UIL的內存緩存默認使用了LRU算法,即最近最少使用算法,選用了基于鏈表結構的LinkedHashMap作為存儲結構,初始化LinkedHashMap對象,并按照使用順序來排序,accessOrder = true;