那些我們用過的Android開源圖片加載框架

一、UniversalImageLoader

https://github.com/nostra13/Android-Universal-Image-Loader

UIL可以算是老牌最火的圖片加載庫了,使用過這個框架的項目可以說多到教你做人,我第一次把第三方開源圖片加載框架加入項目中的就是這個了,當時感覺瞬間逼格上漲,媽媽再也不用擔心出現OOM和ListView圖片錯亂了。可惜的是該作者在項目中說明已經停止了對該項目的維護。這就意味著以后任何的 bug 都不會修復,任何的新特性都不會再繼續開發,所以毫無疑問 UIL 不推薦在項目中使用了。

使用方法:

1、在Application全局變量中的進行配置ImageLoaderConfiguration,有選擇性的進行配置,具體代碼如下:

ImageLoaderConfiguration config =newImageLoaderConfiguration.Builder(context)

.memoryCacheExtraOptions(480, 800)// default = device screen dimensions

.discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75)

.taskExecutor(AsyncTask.THREAD_POOL_EXECUTOR)

.taskExecutorForCachedImages(AsyncTask.THREAD_POOL_EXECUTOR)

.threadPoolSize(3)// default線程池數量

.threadPriority(Thread.NORM_PRIORITY - 1)// default

.tasksProcessingOrder(QueueProcessingType.FIFO)// default

.denyCacheImageMultipleSizesInMemory()

.memoryCache(newLruMemoryCache(2 * 1024 * 1024))//內存緩存

.memoryCacheSize(2 * 1024 * 1024)

.discCache(newUnlimitedDiscCache(cacheDir))// 磁盤緩存

.discCacheSize(50 * 1024 * 1024)

.discCacheFileCount(100)

.discCacheFileNameGenerator(newHashCodeFileNameGenerator())// default

.imageDownloader(newBaseImageDownloader(context))// default

.imageDecoder(newBaseImageDecoder())// default

.defaultDisplayImageOptions(DisplayImageOptions.createSimple())// default

.enableLogging()

.build();

2、針對每次加載任務進行配置DisplayImageOptions

DisplayImageOptions options =newDisplayImageOptions.Builder()

.showStubImage(R.drawable.ic_stub)

.showImageForEmptyUri(R.drawable.ic_empty)

.showImageOnFail(R.drawable.ic_error)

.resetViewBeforeLoading()

.delayBeforeLoading(1000)

.cacheInMemory()

.cacheOnDisc()

.preProcessor(...)

.postProcessor(...)

.extraForDownloader(...)

.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)// default

.bitmapConfig(Bitmap.Config.ARGB_8888)// default

.decodingOptions(...)

.displayer(newSimpleBitmapDisplayer())// default

.handler(newHandler())// default

.build();

UIL支持的圖片加載格式如下:

String imageUri ="http://site.com/image.png"; // from Web

String imageUri ="file:///mnt/sdcard/image.png"; // from SD card

String imageUri ="content://media/external/audio/albumart/13"; // from content provider

String imageUri ="assets://image.png"; // from assets

String imageUri ="drawable://"+ R.drawable.image; // from drawables (only images, non-9patch)

配置好后調用imageLoader.displayImage方法就OK了,妥妥的!

下面簡單分析一下,UIL框架的加載原理:

1、ImageLoader圖片加載器,對外的主要 API,采取了單例模式,用于圖片的加載和顯示。

2、MemoryCache圖片內存換成。默認使用了 LRU 算法。 LRU: Least Recently Used 近期最少使用算法, 選用了基于鏈表結構的 LinkedHashMap 作為存儲結構。假設情景:內存緩存設置的閾值只夠存儲兩個 bitmap 對象,當 put 第三個 bitmap 對象時,將近期最少使用的 bitmap 對象移除。

3、DiskCache圖片磁盤緩存,默認使用LruDiskCache算法,在緩存滿時刪除最近最少使用的圖片;緩存目錄下名為journal的文件記錄緩存的所有操作

4、圖片加載流程

1.判斷圖片的內存緩存是否存在,若存在直接執行步驟 8;

2.判斷圖片的磁盤緩存是否存在,若存在直接執行步驟 5;

3.ImageDownloader從網絡上下載圖片;

4.將圖片緩存在磁盤上;

5.ImageDecoder將圖片 decode 成 bitmap 對象;

6.BitmapProcessor根據DisplayImageOptions配置對圖片進行預處理(Pre-process Bitmap);

7.將 bitmap 對象緩存到內存中;

8.根據DisplayImageOptions配置對圖片進行后處理(Post-process Bitmap);

9.執行DisplayBitmapTask將圖片顯示在相應的控件上。

二、Picasso

https://github.com/square/picasso

Picasso是Square公司開源的一個Android平臺上的圖片加載框架,簡單易用,一句話搞定項目中的圖片加載,好用到令人發指。

使用一句話:Picasso.with(this).load("url").placeholder(R.mipmap.ic_default).into(imageView);

原理簡要分析:

1、Picasso.with(Context):入手

public static Picasso with(Contextcontext){

? ? ? ? ? ?if(singleton==null){

? ? ? ? ? ? ? ? ? ?synchronized(Picasso.class){

? ? ? ? ? ? ? ? ? ? ? if(singleton==null){

? ? ? ? ? ? ? ? ? ? ? ? ?singleton=newBuilder(context).build();

? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ?}

return singleton;}

單列模式,保證多線程情況下,也只有一個實例。

/** Create the {@link Picasso} instance. 創建Picasso的實例 */

public Picassobuild(){

Context context=this.context;

if(downloader==null){

downloader=Utils.createDefaultDownloader(context);

}

if(cache==null){

cache=new LruCache(context);

}

if(service==null){

service=new PicassoExecutorService();

}

if(transformer==null){

transformer=RequestTransformer.IDENTITY;

}

Stats stats=newStats(cache);

Dispatcher dispatcher=new Dispatcher(context,service,HANDLER,downloader,cache,stats);

return new Picasso(context,dispatcher,cache,listener,transformer,

requestHandlers,stats,indicatorsEnabled,loggingEnabled);

}

默認初始化了以下的參數:

Downloader

DownLoader就是下載用的工具類,在Picasso當中,如果OKHttp可以使用的話,就會默認使用OKHttp,如果無法使用的話,就會使用UrlConnectionDownloader(默認使用HttpURLConnection實現)。

Cache

默認實現為LruCache,就是使用LinkedHashMap實現的一個Cache類,注意的一個地方就是,在其他的地方,我們一般默認的是限制的capacity,但是這個地方我們是限制的總共使用的內存空間。因此LruCache在實現的時候,其實簡單理解就是將LinkedHashMap封裝,然后基于LinkedHashMap的方法實現Cache的方法,在Cache的set()方法的時候,會不斷計算當前還可以使用的空間大小,要是超出范圍,則刪除之前保存的數據。

ExecutorService

默認的實現為PicassoExecutorService,該類也比較簡單,其實就是ThreadPoolExecutor,在其功能的基礎上繼續封裝,在其中有一個比較細心的功能就是,Picasso通過PicassoExecutorService設置線程數量,來調整在2G/3G/4G/WiFi不同網絡情況下的不同表現。

RequestTransformer

ReqeustTransformer是一個接口,用來預處理Reqeust,可以用來將請求進行預先處理,比如改個域名啥的。

Stats

主要是一些統計信息,比如cache hit/miss,總共下載的文件大小,下載過的圖片數量,轉換的圖片數量等等。

Dispatcher

Picasso當中,分發任務的線程,這是我們以后要重點研究的一個類,先標記一下,這個Dispatcher主要做了以下的事情:

啟動了一個DispatcherThread線程初始化了一個用來處理消息的DispatcherHandler,注意,根據Dispatcher中默認配置,該Handler所有數據的處理是在DispatcherThread之上。初始化并注冊了一個網絡狀態廣播接收器。


2、圖片加載流程:

1.初始化Picasso,實例化其唯一的對象。

2.根據傳入的Url、File、resource Id,構建ReqeustCreator對象

3.根據ReqeustCreator構建Request對象,同時根據Reqeust屬性,嘗試從Cache中訪問數據

4.Cache Hit,則通過回調,設置Target或者ImageView,完成該Reqeust

5.如果Cache Miss,那么則構建相應的Action,并提交到DispatcherThread當中。

6.Dispatcher中的Handler接收到相應的Message,調用dispatcher.performSubmit(action)進行處理。

7.創建BitmapHunter對象,并提交到PicassoExecutorService線程池

8.再次檢查Memory Cache中已經有緩存,如果Hit,則讀取緩存中的Bitmap

9.如果Cache miss,則交給Action對應的ReqeustHandler進行處理,比如網絡請求,或者從File讀取圖片

10.返回結果之后,通知Dispatcher中的Handler處理結果。

11.DispatcherThread中將BitmapHunter的結果打包(batch),最快200ms打包一次。通知主線程HANDLER進行處理

12.主線程HANDLER接收打包的BitmapHunter,對最后的結果進行分發。

注意:Picasso框架沒有實現磁盤緩存,配合OkHttp進行實現。

三、Glide

https://github.com/bumptech/glide

Glide 是 Google 一位員工的大作,他完全是基于 Picasso 的,沿襲了 Picasso 的簡潔風格,但是在此做了大量優化與改進。

Glide 默認的 Bitmap 格式是 RGB_565 格式,而 Picasso 默認的是 ARGB_8888 格式,這個內存開銷要小一半。

在磁盤緩存方面,Picasso 只會緩存原始尺寸的圖片,而 Glide 緩存的是多種規格,也就意味著 Glide 會根據你 ImageView 的大小來緩存相應大小的圖片尺寸,比如你 ImageView 大小是200*200,原圖是 400*400 ,而使用 Glide 就會緩存 200*200 規格的圖,而 Picasso 只會緩存 400*400 規格的。這個改進就會導致 Glide 比 Picasso 加載的速度要快,畢竟少了每次裁剪重新渲染的過程。

最重要的一個特性是 Glide 支持加載 Gif 動態圖,而 Picasso 不支持該特性。

除此之外,還有很多其他配置選項的增加。

總體來說,Glide 是在 Picasso 基礎之上進行的二次開發,各個方面做了不少改進,不過這也導致他的包比 Picasso 大不少,不過也就不到 500k,Picasso 是100多k,方法數也比 Picasso 多不少,不過畢竟級別還是蠻小的,影響不是很大。

四、Fresco

https://github.com/facebook/fresco


Fresco 是 Facebook 出品,他是新一代的圖片加載庫,我們知道 Android 應用程序可用的內存有限,經常會因為圖片加載導致 OOM,雖然我們有各種手段去優化,盡量減少出現 OOM 的可能性,但是永遠沒法避免,尤其某些低端手機 OOM 更是嚴重。而 Facebook 就另辟蹊徑,既然沒法在 Java 層處理,我們就在更底層的 Native 堆做手腳。于是 Fresco 將圖片放到一個特別的內存區域叫 Ashmem 區,就是屬于 Native 堆,圖片將不再占用 App 的內存,Java 層對此無能為力,這里是屬于 C++ 的地盤,所以能大大的減少 OOM。

本人四個庫都使用了一遍,對比到Fresco確實強大,加載大圖Fresco最屌,有的圖Glide和Picasso加載不出來,換上Fresco妥妥的,不過Fresco比較龐大,推薦在主要都是圖片的app中使用,一般的app使用Glide和Picasso就夠了!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容