圖片加載理解之 UIL

針對Android 的圖片加載,有著太多的細節問題,需要注意,本文針對 Universal Image Loader 的一些技術點,進行細致的剖析一番。由于涉及的內容,所以打算分成三個系列,分別從視圖(View),數據(Cache),網絡等三個大的方面講起:

視圖

1. ImageLoader是如何實現對ImageView的包裝的?

1)ImageAware:針對 ImageView 行為的抽象—接口,獲取 ImageView 的寬度、高度、scaleType、id;以及包裝的ImageView,設定圖片; 2)ViewAware: 抽象類,實現ImageAware。提供了ViewRef的屬性,來持有ImageView的弱引用;實現方式:this.viewRef = new WeakReference (view)。

使用弱引用的目的,避免了異步耗時任務對 ImageView 的強引用,能夠使 ImageView 能夠被及時回收,防止內存泄露的發生(雖然很短暫的一瞬間)。

2. 在 ListView 加載顯示圖片的時候,當一個正在加載圖片的 View 被滑出屏幕,ImageLoader 是否會取消此次下載圖片任務,是如何取消的?

首先在加載獲取圖片時,是通過 ImageLoaderEngine 來進行提交進行的。在 ImageLoaderEngine 是啟動線程池來異步加載圖片,分別從內存、磁盤、網絡中進行獲取。而在這幾步之前,會首先進行 View 是否被回收的判斷,若是被回收,則拋出異常,并調用相應 listener 的 cancel 方法。

3. 在 ListView 的滑動過程中,如何暫停所有的圖片加載任務?

在 ImageLoader 中,其提供了一個 PauseOnScrollListener 的類,在使用 ListView 的時,只需進行設置即可。

其實現原理則是在通過調用 ImageLoader 的 pause 和 resume 方法,在調用圖片加載的第一步會進行判斷,是否設置了 暫停 狀態,如果設置了,則會通過對象鎖 pauseLock 的 wait 方法,來使當前圖片加載線程處于阻塞狀態;當調用了 resume 方法,則會調用了 pauseLock 的 notifyAll 方法,來恢復線程的執行。

這樣做的作用是達到 CPU 資源的充分利用,通過暫停異步圖片加載的線程,來不使 UI 線程卡頓,提高 ListView 在滑動過程的流暢程度。

4. 怎樣針對 View 的特定大小,處理獲取到圖片的大小?

在 ImageLoader 調用 displayImage 方法時,在指定相應的 ImageView 時,也可以傳遞一個 ImageSize 的參數,用來指定所需顯示的圖片的大小;若是不傳的話,則會獲取 ImageView 的 width 及 height,若獲取到的值為 0,那么這個相應 ImageSize 的寬與高則會取屏幕的寬與高。

另外,在對圖片進行緩存時,生成相應的緩存 Key 的值是根據圖片的 uri 和 targetSize (指定的圖片大小)來生成的,所以,不同大小的 ImageView 獲取到的 bitmap 則是不同的,即從緩存中拿到的是不同的。

這里,可以看出相應大小的 ImageView 與內存的緩存中的不同的 bitmap 是相對應的。而 diskCache 中則是以 uri 為鍵值的磁盤文件。另外,由磁盤文件轉換為相應的 bitmap 則是對應下面問題的答案。

5. 圖片是如何進行壓縮的?

我們知道圖片加載到內存之中,是以 Bitmap 的形式存在的。而在 Android App 中,內存是非常稀缺的資源。所以當加載大圖片時,需要根據當前顯示圖片的控件,采用相應手段,只在內存中加載出來相應大小的 Bitmap ,來避免 Out Of Memory 的發生。

這里采用 BitmapFactory 來進行圖片文件轉換至 Bitmap 對象,通過其 decodeStream 方法,若是我們傳遞的參數 Options,其指定了 inJustDecodeBounds 為 true, 則只會獲取圖片的大小(并不會生成 Bitmap 對象),其輸出值為 Options 對象的 outWidth 和 outHeight 。

根據獲取到的圖片大小,以及我們要顯示圖片的 View 的大小,便可計算出我們需要對圖片進行縮放的比例,即指定 Options 參數的 inSampleSize 的值。(此時 inJustDecodeBounds 的值為 false)這樣獲取到的 Bitmap 對象就是進行縮放調整過的圖像。

這一步便是 Android 中調整 Bitmap 大小,減少內存消耗關鍵性的一步。

數據

數據主要體現在對圖片的緩存處理。UIL 對圖片的緩存為三級緩存,一是內存,二是磁盤,三是網絡(遠程的服務器)。

在內存中保存的為 Bitmap 對象,其是根據相應的 View 和 View 大小為 Key 值的。即加載的是同一張圖片的兩個不同大小的 View,會在內存緩存中存在針對這張圖片的兩個 Bitmap 對象。而磁盤中緩存的則只有這一張圖片文件,即從遠程服務器中下載到本地的圖片文件。

若是本地磁盤中沒有響應的圖片文件的話,則會通過網絡從遠程服務器中下載圖片至本地。

網絡

從網絡中獲取圖片,UIL 使用的是 HttpURLConnection ,來執行圖片的獲取下載。對應邏輯代碼是在 ImageLoader 接口中,其定義了由圖片 imageUri,來得到 InputStream 。另外以指定 Scheme 的方式(如 HTTP,FILE,ASSETS,DRAWABLE) 來得到圖片的輸入流。

總結

UIL 作為圖片加載的入門庫,其邏輯代碼也是寫的非常漂亮。結構化清晰,簡單明了,對各個模塊都由一個接口來定義,極大地豐富細節的實現,像不同的內存、磁盤緩存策略及圖片下載獲取方式,另外這些策略都可以在 ImageLoader 的配置策略進行修改。總之,這個庫是一個不錯的學習 Android 圖片加載的資料。

參考資料

 

來自:http://alighters.com/blog/2017/01/25/understand-imageloader/

 

 本文由用戶 AlyceHalse 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!