Android開源圖片加載框架

一、UniversalImageLoader

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

UIL可以算是老牌最火的圖片加載庫了殉农,使用過這個(gè)框架的項(xiàng)目可以說多到教你做人乒融,我第一次把第三方開源圖片加載框架加入項(xiàng)目中的就是這個(gè)了,當(dāng)時(shí)感覺瞬間逼格上漲,媽媽再也不用擔(dān)心出現(xiàn)OOM和ListView圖片錯亂了∥悖可惜的是該作者在項(xiàng)目中說明已經(jīng)停止了對該項(xiàng)目的維護(hù)。這就意味著以后任何的 bug 都不會修復(fù)薄翅,任何的新特性都不會再繼續(xù)開發(fā),所以毫無疑問 UIL 不推薦在項(xiàng)目中使用了氓奈。

使用方法:

1翘魄、在Application全局變量中的進(jìn)行配置ImageLoaderConfiguration,有選擇性的進(jìn)行配置,具體代碼如下:

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線程池?cái)?shù)量

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

.tasksProcessingOrder(QueueProcessingType.FIFO)// default

.denyCacheImageMultipleSizesInMemory()

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

.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舀奶、針對每次加載任務(wù)進(jìn)行配置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)

配置好后調(diào)用imageLoader.displayImage方法就OK了暑竟,妥妥的!

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

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

2南蓬、MemoryCache圖片內(nèi)存換成纺非。默認(rèn)使用了 LRU 算法。 LRU: Least Recently Used 近期最少使用算法, 選用了基于鏈表結(jié)構(gòu)的 LinkedHashMap 作為存儲結(jié)構(gòu)赘方。假設(shè)情景:內(nèi)存緩存設(shè)置的閾值只夠存儲兩個(gè) bitmap 對象烧颖,當(dāng) put 第三個(gè) bitmap 對象時(shí),將近期最少使用的 bitmap 對象移除窄陡。

3炕淮、DiskCache圖片磁盤緩存,默認(rèn)使用LruDiskCache算法跳夭,在緩存滿時(shí)刪除最近最少使用的圖片涂圆;緩存目錄下名為journal的文件記錄緩存的所有操作

4、圖片加載流程

1.判斷圖片的內(nèi)存緩存是否存在优妙,若存在直接執(zhí)行步驟 8乘综;

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

3.ImageDownloader從網(wǎng)絡(luò)上下載圖片卡辰;

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

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

6.BitmapProcessor根據(jù)DisplayImageOptions配置對圖片進(jìn)行預(yù)處理(Pre-process Bitmap)九妈;

7.將 bitmap 對象緩存到內(nèi)存中反砌;

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

9.執(zhí)行DisplayBitmapTask將圖片顯示在相應(yīng)的控件上萌朱。

二宴树、Picasso

https://github.com/square/picasso

Picasso是Square公司開源的一個(gè)Android平臺上的圖片加載框架,簡單易用晶疼,一句話搞定項(xiàng)目中的圖片加載酒贬,好用到令人發(fā)指。

使用一句話: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;}

單列模式,保證多線程情況下锭吨,也只有一個(gè)實(shí)例。

/** Create the {@link Picasso} instance. 創(chuàng)建Picasso的實(shí)例 */

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);

}

默認(rèn)初始化了以下的參數(shù):

Downloader

DownLoader就是下載用的工具類寒匙,在Picasso當(dāng)中零如,如果OKHttp可以使用的話,就會默認(rèn)使用OKHttp锄弱,如果無法使用的話考蕾,就會使用UrlConnectionDownloader(默認(rèn)使用HttpURLConnection實(shí)現(xiàn))。

Cache

默認(rèn)實(shí)現(xiàn)為LruCache会宪,就是使用LinkedHashMap實(shí)現(xiàn)的一個(gè)Cache類肖卧,注意的一個(gè)地方就是,在其他的地方狈谊,我們一般默認(rèn)的是限制的capacity喜命,但是這個(gè)地方我們是限制的總共使用的內(nèi)存空間。因此LruCache在實(shí)現(xiàn)的時(shí)候河劝,其實(shí)簡單理解就是將LinkedHashMap封裝壁榕,然后基于LinkedHashMap的方法實(shí)現(xiàn)Cache的方法,在Cache的set()方法的時(shí)候赎瞎,會不斷計(jì)算當(dāng)前還可以使用的空間大小牌里,要是超出范圍,則刪除之前保存的數(shù)據(jù)务甥。

ExecutorService

默認(rèn)的實(shí)現(xiàn)為PicassoExecutorService牡辽,該類也比較簡單,其實(shí)就是ThreadPoolExecutor敞临,在其功能的基礎(chǔ)上繼續(xù)封裝态辛,在其中有一個(gè)比較細(xì)心的功能就是,Picasso通過PicassoExecutorService設(shè)置線程數(shù)量挺尿,來調(diào)整在2G/3G/4G/WiFi不同網(wǎng)絡(luò)情況下的不同表現(xiàn)奏黑。

RequestTransformer

ReqeustTransformer是一個(gè)接口炊邦,用來預(yù)處理Reqeust,可以用來將請求進(jìn)行預(yù)先處理熟史,比如改個(gè)域名啥的馁害。

Stats

主要是一些統(tǒng)計(jì)信息,比如cache hit/miss蹂匹,總共下載的文件大小碘菜,下載過的圖片數(shù)量,轉(zhuǎn)換的圖片數(shù)量等等限寞。

Dispatcher

Picasso當(dāng)中忍啸,分發(fā)任務(wù)的線程,這是我們以后要重點(diǎn)研究的一個(gè)類昆烁,先標(biāo)記一下吊骤,這個(gè)Dispatcher主要做了以下的事情:

啟動了一個(gè)DispatcherThread線程初始化了一個(gè)用來處理消息的DispatcherHandler,注意静尼,根據(jù)Dispatcher中默認(rèn)配置,該Handler所有數(shù)據(jù)的處理是在DispatcherThread之上传泊。初始化并注冊了一個(gè)網(wǎng)絡(luò)狀態(tài)廣播接收器鼠渺。

2、圖片加載流程:

1.初始化Picasso眷细,實(shí)例化其唯一的對象拦盹。

2.根據(jù)傳入的Url、File溪椎、resource Id普舆,構(gòu)建ReqeustCreator對象

3.根據(jù)ReqeustCreator構(gòu)建Request對象,同時(shí)根據(jù)Reqeust屬性校读,嘗試從Cache中訪問數(shù)據(jù)

4.Cache Hit沼侣,則通過回調(diào),設(shè)置Target或者ImageView歉秫,完成該Reqeust

5.如果Cache Miss蛾洛,那么則構(gòu)建相應(yīng)的Action,并提交到DispatcherThread當(dāng)中雁芙。

6.Dispatcher中的Handler接收到相應(yīng)的Message轧膘,調(diào)用dispatcher.performSubmit(action)進(jìn)行處理。

7.創(chuàng)建BitmapHunter對象兔甘,并提交到PicassoExecutorService線程池

8.再次檢查Memory Cache中已經(jīng)有緩存谎碍,如果Hit,則讀取緩存中的Bitmap

9.如果Cache miss洞焙,則交給Action對應(yīng)的ReqeustHandler進(jìn)行處理蟆淀,比如網(wǎng)絡(luò)請求拯啦,或者從File讀取圖片

10.返回結(jié)果之后,通知Dispatcher中的Handler處理結(jié)果扳碍。

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

12.主線程HANDLER接收打包的BitmapHunter笋敞,對最后的結(jié)果進(jìn)行分發(fā)碱蒙。

注意:Picasso框架沒有實(shí)現(xiàn)磁盤緩存,配合OkHttp進(jìn)行實(shí)現(xiàn)夯巷。

三赛惩、Glide

https://github.com/bumptech/glide

Glide 是 Google 一位員工的大作,他完全是基于 Picasso 的趁餐,沿襲了 Picasso 的簡潔風(fēng)格喷兼,但是在此做了大量優(yōu)化與改進(jìn)。

Glide 默認(rèn)的 Bitmap 格式是 RGB_565 格式后雷,而 Picasso 默認(rèn)的是 ARGB_8888 格式季惯,這個(gè)內(nèi)存開銷要小一半。

在磁盤緩存方面臀突,Picasso 只會緩存原始尺寸的圖片勉抓,而 Glide 緩存的是多種規(guī)格,也就意味著 Glide 會根據(jù)你 ImageView 的大小來緩存相應(yīng)大小的圖片尺寸候学,比如你 ImageView 大小是200*200藕筋,原圖是 400*400 ,而使用 Glide 就會緩存 200*200 規(guī)格的圖梳码,而 Picasso 只會緩存 400*400 規(guī)格的隐圾。這個(gè)改進(jìn)就會導(dǎo)致 Glide 比 Picasso 加載的速度要快,畢竟少了每次裁剪重新渲染的過程掰茶。

最重要的一個(gè)特性是 Glide 支持加載 Gif 動態(tài)圖暇藏,而 Picasso 不支持該特性。

除此之外符匾,還有很多其他配置選項(xiàng)的增加叨咖。

總體來說,Glide 是在 Picasso 基礎(chǔ)之上進(jìn)行的二次開發(fā)啊胶,各個(gè)方面做了不少改進(jìn)甸各,不過這也導(dǎo)致他的包比 Picasso 大不少,不過也就不到 500k焰坪,Picasso 是100多k趣倾,方法數(shù)也比 Picasso 多不少,不過畢竟級別還是蠻小的某饰,影響不是很大儒恋。

四善绎、Fresco

https://github.com/facebook/fresco

Fresco 是 Facebook 出品,他是新一代的圖片加載庫诫尽,我們知道 Android 應(yīng)用程序可用的內(nèi)存有限禀酱,經(jīng)常會因?yàn)閳D片加載導(dǎo)致 OOM,雖然我們有各種手段去優(yōu)化牧嫉,盡量減少出現(xiàn) OOM 的可能性剂跟,但是永遠(yuǎn)沒法避免,尤其某些低端手機(jī) OOM 更是嚴(yán)重酣藻。而 Facebook 就另辟蹊徑曹洽,既然沒法在 Java 層處理,我們就在更底層的 Native 堆做手腳辽剧。于是 Fresco 將圖片放到一個(gè)特別的內(nèi)存區(qū)域叫 Ashmem 區(qū)送淆,就是屬于 Native 堆,圖片將不再占用 App 的內(nèi)存怕轿,Java 層對此無能為力偷崩,這里是屬于 C++ 的地盤,所以能大大的減少 OOM撞羽。

本人四個(gè)庫都使用了一遍环凿,對比到Fresco確實(shí)強(qiáng)大,加載大圖Fresco最屌放吩,有的圖Glide和Picasso加載不出來,換上Fresco妥妥的羽杰,不過Fresco比較龐大渡紫,推薦在主要都是圖片的app中使用,一般的app使用Glide和Picasso就夠了考赛!

文/水跡(簡書作者)

原文鏈接:http://www.reibang.com/p/3ac30878c72c

著作權(quán)歸作者所有惕澎,轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),并標(biāo)注“簡書作者”颜骤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唧喉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子忍抽,更是在濱河造成了極大的恐慌八孝,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸠项,死亡現(xiàn)場離奇詭異干跛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祟绊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門楼入,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哥捕,“玉大人,你說我怎么就攤上這事嘉熊∫W” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵阐肤,是天一觀的道長凫佛。 經(jīng)常有香客問我,道長泽腮,這世上最難降的妖魔是什么御蒲? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任恍风,我火速辦了婚禮串慰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘托猩。我一直安慰自己碧磅,他們只是感情好碘箍,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鲸郊,像睡著了一般丰榴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秆撮,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天四濒,我揣著相機(jī)與錄音,去河邊找鬼职辨。 笑死盗蟆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舒裤。 我是一名探鬼主播喳资,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腾供!你這毒婦竟也來了仆邓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤伴鳖,失蹤者是張志新(化名)和其女友劉穎节值,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黎侈,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡察署,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了峻汉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贴汪。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脐往,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扳埂,到底是詐尸還是另有隱情业簿,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布阳懂,位于F島的核電站梅尤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏岩调。R本人自食惡果不足惜巷燥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望号枕。 院中可真熱鬧缰揪,春花似錦、人聲如沸葱淳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赞厕。三九已至艳狐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間皿桑,已是汗流浹背毫目。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诲侮,地道東北人蒜茴。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像浆西,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子顽腾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容