Android 常見的圖片加載框架詳細(xì)介紹
Android 常見的圖片加載框架
圖片加載涉及到圖片的緩存、圖片的處理、圖片的顯示等。而隨著市面上手機(jī)設(shè)備的硬件水平飛速發(fā)展,對(duì)圖片的顯示要求越來越高,稍微處理不好就會(huì)造成內(nèi)存溢出等問題。很多軟件廠家的通用做法就是借用第三方的框架進(jìn)行圖片加載。 開源框架的源碼還是挺復(fù)雜的,但使用較為簡(jiǎn)單。大部分框架其實(shí)都差不多,配置稍微麻煩點(diǎn),但是使用時(shí)一般只需要一行,顯示方法一般會(huì)提供多個(gè)重載方法,支持不同需要。這樣會(huì)減少很不必要的麻煩。同時(shí),第三方框架的使用較為方便,這大大的減少了工作量、提高了開發(fā)效率。本文主要介紹四種常用的圖片加載框架,分別是Fresco、ImageLoader、 Picasso、 Glide,包括他們各自的優(yōu)缺點(diǎn)、使用步驟等等。
首先看 Fresco, Fresco 是 Facebook 推出的開源圖片緩存工具,主要特點(diǎn)包括:兩個(gè)內(nèi)存緩存加上 Native 緩存構(gòu)成了三級(jí)緩存,支持流式,可以類似網(wǎng)頁上模糊漸進(jìn)式顯示圖片,對(duì)多幀動(dòng)畫圖片支持更好,如 Gif、WebP。它的優(yōu)點(diǎn)是其他幾個(gè)框架沒有的, 或者說是其他幾個(gè)框架的短板。
優(yōu)點(diǎn):
1. 圖片存儲(chǔ)在安卓系統(tǒng)的匿名共享內(nèi)存, 而不是虛擬機(jī)的堆內(nèi)存中, 圖片的中間緩沖數(shù)據(jù)也存放在本地堆內(nèi)存, 所以, 應(yīng)用程序有更多的內(nèi)存使用, 不會(huì)因?yàn)閳D片加載而導(dǎo)致oom, 同時(shí)也減少垃圾回收器頻繁調(diào)用回收 Bitmap 導(dǎo)致的界面卡頓, 性能更高。
2. 漸進(jìn)式加載 JPEG 圖片, 支持圖片從模糊到清晰加載。
3. 圖片可以以任意的中心點(diǎn)顯示在 ImageView, 而不僅僅是圖片的中心。
4. JPEG 圖片改變大小也是在 native 進(jìn)行的, 不是在虛擬機(jī)的堆內(nèi)存, 同樣減少 OOM。
5. 很好的支持 GIF 圖片的顯示。
缺點(diǎn):
1. 框架較大, 影響 Apk 體積
2. 使用較繁瑣
使用步驟:
1. 引入 Fresco,包括兩種方式,在線和離線。
在線引入依賴腳本形式,在dependencies中添加依賴,
compile 'com.facebook.fresco:fresco:0.9.0'
引入離線引入,需要導(dǎo)入的arr包較多,包括:
compile(name: 'drawee-0.9.0', ext: 'aar')
compile(name: 'fbcore-0.9.0', ext: 'aar')
compile(name: 'imagepipeline-0.9.0', ext: 'aar')
compile(name: 'imagepipeline-base-0.9.0', ext: 'aar')
compile files('libs/bolts-android-1.1.4.jar')
上面提到的aar其實(shí)就是lib module壓縮包的形式,包括.class和相關(guān)的資源文件,平常使用的jar僅僅包括.class文件。使用aar包時(shí),還需要來到project `build.gradle`里面, 在allprojects方法體加入
allprojects {
repositories {
jcenter()
//add begin
flatDir {
dirs 'libs'
}
//add end
}
2. 需要在程序入口方法里面進(jìn)行初始化。在oncreate方法中添加初始化語句。
Fresco.initialize(context);
3. 在布局文件中,需要使用圖片展示地方,使用它定義的控件
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/iv_img"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@mipmap/ic_launcher"
fresco:fadeDuration="300"
fresco:roundingBorderColor="#ccc"
fresco:roundingBorderWidth="2dp"/>
4.設(shè)置靜態(tài)圖片,在代碼中具體寫如下代碼
// 圖片加載
Uri uri = Uri.parse(data.url);
holder.ivIcon.setImageURI(uri);
5. 設(shè)置gif圖片,在代碼中具體寫如下代碼
DraweeController gifController = Fresco.newDraweeControllerBuilder().setUri(uri)
.setAutoPlayAnimations(true).build();
holder.ivIcon.setController(gifController);
ImageLoader是比較老的框架,是github社區(qū)上star最多的一個(gè)項(xiàng)目,可以理解為點(diǎn)贊最多滴,應(yīng)該是最有名的一個(gè)國內(nèi)很多知名軟件都用它包括淘寶京東聚劃算等等。整個(gè)庫分為 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大模塊,其中 Cache 分為 MemoryCache 和 DiskCache 兩部分。簡(jiǎn)單的講就是 ImageLoader 收到加載及顯示圖片的任務(wù),并將它交給 ImageLoaderEngine,ImageLoaderEngine 分發(fā)任務(wù)到具體線程池去執(zhí)行,任務(wù)通過 Cache 及 ImageDownloader 獲取圖片,中間可能經(jīng)過 BitmapProcessor 和 ImageDecoder 處理,最終轉(zhuǎn)換為Bitmap 交給 BitmapDisplayer 在 ImageAware中顯示。特點(diǎn)是穩(wěn)定, 加載速度適中, 缺點(diǎn)在于不支持GIF圖片加載, 使用稍微繁瑣, 并且緩存機(jī)制沒有和 http 的緩存很好的結(jié)合, 完全是自己的一套緩存機(jī)制。使用比較簡(jiǎn)單,這個(gè)框架的github主頁上也有快速使用的步驟,基本上就是在application類里的oncreate方法(整個(gè)程序開始時(shí)運(yùn)行一次)中進(jìn)行一下簡(jiǎn)單的基本配置,可以根據(jù)需要自行進(jìn)行設(shè)定,懶得設(shè)定的話框架也提供了一個(gè)默認(rèn)的配置,調(diào)用一個(gè)方法即可?;旧鲜桥渲靡恍╊愃朴?緩存類型啊,緩存上限值啊,加載圖片的線程池?cái)?shù)量啊等等。此外在頁面內(nèi)顯示的時(shí)候還要設(shè)置一個(gè)顯示配置這個(gè)配置不同于基本配置,一個(gè)項(xiàng)目里可以根據(jù)需要?jiǎng)?chuàng)建多個(gè)配置對(duì)象使用,這個(gè)配置就比較具體了,可以設(shè)置是否使用disk緩存(存到sd卡里一般),加載圖片失敗時(shí)顯示的圖片,默認(rèn)圖片,圖片的色彩樣式等。ImageLoader和Volley圖片部分還包括其他大部分圖片框架,基本上圖片處理都差不多,區(qū)別僅在于部分優(yōu)化了,而優(yōu)化方面UIL即Universal-Image-Loader框架做的最好,配置好以后,就是簡(jiǎn)單的使用了,創(chuàng)建一個(gè)圖片加載對(duì)象,然后一行代碼搞定顯示圖片功能。參數(shù)一般是入你需要顯示的圖片url和imageview對(duì)象。
優(yōu)點(diǎn):
1.支持下載進(jìn)度監(jiān)聽
2.可以在 View 滾動(dòng)中暫停圖片加載,通過 PauseOnScrollListener 接口可以在 View 滾動(dòng)中暫停圖片加載。
3.默認(rèn)實(shí)現(xiàn)多種內(nèi)存緩存算法 這幾個(gè)圖片緩存都可以配置緩存算法,不過 ImageLoader 默認(rèn)實(shí)現(xiàn)了較多緩存算法,如 Size 最大先刪除、使用最少先刪除、最近最少使用、先進(jìn)先刪除、時(shí)間最長先刪除等。
4.支持本地緩存文件名規(guī)則定義
使用步驟:
1. 在Application子類中的onCreate方法中初始化ImageLoaderConfiguration
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)// .threadPriority(Thread.NORM_PRIORITY - 2)// .denyCacheImageMultipleSizesInMemory()// .diskCacheFileNameGenerator(new Md5FileNameGenerator())// .diskCacheSize(50 * 1024 * 1024) // 50 Mb .memoryCache(new LruMemoryCache(4 * 1024 * 1024)).tasksProcessingOrder(QueueProcessingType.LIFO)// .writeDebugLogs() // Remove for release app .build(); // Initialize ImageLoader with configuration. ImageLoader.getInstance().init(config);
2. 在具體的地方直接
//圖片加載
// ImageLoader.getInstance().displayImage(data.url, holder.ivIcon);
DisplayImageOptions option = new DisplayImageOptions.Builder()
.resetViewBeforeLoading(true)
.cacheOnDisk(true)
.imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565)
.considerExifParams(true)
.displayer(new FadeInBitmapDisplayer(300))
.build();
ImageLoader.getInstance().displayImage(data.url, holder.ivIcon, option);
3. 加載各種格式圖片
String imageUri = "http://site.com/image.png"; // 網(wǎng)絡(luò)圖片 String imageUri = "file:///mnt/sdcard/image.png"; //SD卡圖片 String imageUri = "content://media/external/audio/albumart/13"; // 媒體文件夾 String imageUri = "assets://image.png"; // assets String imageUri = "drawable://" + R.drawable.image; // drawable文件
4. 提供了豐富的緩存策略
內(nèi)存緩存,現(xiàn)在我們來看Universal-Image-Loader有哪些內(nèi)存緩存策略
1. 只使用的是強(qiáng)引用緩存
LruMemoryCache(這個(gè)類就是這個(gè)開源框架默認(rèn)的內(nèi)存緩存類,緩存的是bitmap的強(qiáng)引用,下面我會(huì)從源碼上面分析這個(gè)類)
2.使用強(qiáng)引用和弱引用相結(jié)合的緩存有
UsingFreqLimitedMemoryCache(如果緩存的圖片總量超過限定值,先刪除使用頻率最小的bitmap)
LRULimitedMemoryCache(這個(gè)也是使用的lru算法,和LruMemoryCache不同的是,他緩存的是bitmap的弱引用)
FIFOLimitedMemoryCache(先進(jìn)先出的緩存策略,當(dāng)超過設(shè)定值,先刪除最先加入緩存的bitmap)
LargestLimitedMemoryCache(當(dāng)超過緩存限定值,先刪除最大的bitmap對(duì)象)
LimitedAgeMemoryCache(當(dāng) bitmap加入緩存中的時(shí)間超過我們?cè)O(shè)定的值,將其刪除)
3.只使用弱引用緩存
WeakMemoryCache(這個(gè)類緩存bitmap的總大小沒有限制,唯一不足的地方就是不穩(wěn)定,緩存的圖片容易被回收硬盤緩存)
FileCountLimitedDiscCache(可以設(shè)定緩存圖片的個(gè)數(shù),當(dāng)超過設(shè)定值,刪除掉最先加入到硬盤的文件)
LimitedAgeDiscCache(設(shè)定文件存活的最長時(shí)間,當(dāng)超過這個(gè)值,就刪除該文件)
TotalSizeLimitedDiscCache(設(shè)定緩存bitmap的最大值,當(dāng)超過這個(gè)值,刪除最先加入到硬盤的文件)
UnlimitedDiscCache(這個(gè)緩存類沒有任何的限制)
Picasso 是 Square 開源的項(xiàng)目,且他的主導(dǎo)者是 JakeWharton,所以廣為人知。square公司,很多知名的開源也是該公司`android-times-square,leakcanary,okhttp,retrofit`。 Picasso的使用方便, 一行代碼完成加載圖片并顯示, 框架體積小。但是不支持 GIF, 并且它可能是想讓服務(wù)器去處理圖片的縮放, 它緩存的圖片是未縮放的, 并且默認(rèn)使用 ARGB_8888 格式緩存圖片, 緩存體積大。整個(gè)庫分為 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等模塊。Dispatcher 負(fù)責(zé)分發(fā)和處理 Action,包括提交、暫停、繼續(xù)、取消、網(wǎng)絡(luò)狀態(tài)變化、重試等等。簡(jiǎn)單的講就是 Picasso 收到加載及顯示圖片的任務(wù),創(chuàng)建 Request 并將它交給 Dispatcher,Dispatcher 分發(fā)任務(wù)到具體 RequestHandler,任務(wù)通過 MemoryCache 及 Handler(數(shù)據(jù)獲取接口) 獲取圖片,圖片獲取成功后通過 PicassoDrawable 顯示到 Target 中。需要注意的是上面 Data 的 File system 部分,Picasso 沒有自定義本地緩存的接口,默認(rèn)使用 http 的本地緩存,API 9 以上使用 okhttp,以下使用 Urlconnection,所以如果需要自定義本地緩存就需要重定義 Downloader。
Picasso 優(yōu)點(diǎn)
1.自帶統(tǒng)計(jì)監(jiān)控功能。支持圖片緩存使用的監(jiān)控,包括緩存命中率、已使用內(nèi)存大小、節(jié)省的流量等。
2.支持優(yōu)先級(jí)處理。每次任務(wù)調(diào)度前會(huì)選擇優(yōu)先級(jí)高的任務(wù),比如 App 頁面中 Banner 的優(yōu)先級(jí)高于 Icon 時(shí)就很適用。
3.支持延遲到圖片尺寸計(jì)算完成加載
4.支持飛行模式、并發(fā)線程數(shù)根據(jù)網(wǎng)絡(luò)類型而變。 手機(jī)切換到飛行模式或網(wǎng)絡(luò)類型變換時(shí)會(huì)自動(dòng)調(diào)整線程池最大并發(fā)數(shù),比如 wifi 最大并發(fā)為 4,4g 為 3,3g 為 2。 這里 Picasso 根據(jù)網(wǎng)絡(luò)類型來決定最大并發(fā)數(shù),而不是 CPU 核數(shù)。
5.“無”本地緩存。無”本地緩存,不是說沒有本地緩存,而是 Picasso 自己沒有實(shí)現(xiàn),交給了 Square 的另外一個(gè)網(wǎng)絡(luò)庫 okhttp 去實(shí)現(xiàn),這樣的好處是可以通過請(qǐng)求 Response Header 中的 Cache-Control 及 Expired 控制圖片的過期時(shí)間。
使用步驟:
1. 導(dǎo)入Picasso的jar包,添加依賴
2. 加載圖片
//圖片加載
Picasso.with(mContext) //創(chuàng)建Picasso
.load(data.url) //傳入路徑
.fade(300) //淡化效果時(shí)長
.into(holder.ivIcon); //圖片加載到那個(gè)位置
Glide可以說是 Picasso 的升級(jí)版, 有 Picasso 的優(yōu)點(diǎn), 并且支持 GIF 圖片加載顯示, 圖片緩存也會(huì)自動(dòng)縮放, 默認(rèn)使用 RGB_565 格式緩存圖片, 是 Picasso 緩存體積的一半。谷歌為我們介紹了一個(gè)名叫 Glide 的圖片加載庫,作者是`bumptech`。這個(gè)庫被廣泛的運(yùn)用在google的開源項(xiàng)目中,包括2014年google I/O大會(huì)上發(fā)布的官方app。整個(gè)庫分為 RequestManager(請(qǐng)求管理器),Engine(數(shù)據(jù)獲取引擎)、 Fetcher(數(shù)據(jù)獲取器)、MemoryCache(內(nèi)存緩存)、DiskLRUCache、Transformation(圖片處理)、Encoder(本地緩存存儲(chǔ))、Registry(圖片類型及解析器配置)、Target(目標(biāo)) 等模塊。
簡(jiǎn)單的講就是 Glide 收到加載及顯示資源的任務(wù),創(chuàng)建 Request 并將它交給RequestManager,Request 啟動(dòng) Engine 去數(shù)據(jù)源獲取資源(通過 Fetcher ),獲取到后 Transformation 處理后交給 Target。Glide 依賴于 DiskLRUCache、GifDecoder 等開源庫去完成本地緩存和 Gif 圖片解碼工作。
Glide 優(yōu)點(diǎn)
1.不僅僅可以進(jìn)行圖片緩存還可以緩存媒體文件。Glide 不僅是一個(gè)圖片緩存,它支持 Gif、WebP、縮略圖。甚至是 Video,所以更該當(dāng)做一個(gè)媒體緩存。
2.支持優(yōu)先級(jí)處理。
3.與 Activity/Fragment 生命周期一致,支持 trimMemory。Glide 對(duì)每個(gè) context 都保持一個(gè) RequestManager,通過 FragmentTransaction 保持與 Activity/Fragment 生命周期一致,并且有對(duì)應(yīng)的 trimMemory 接口實(shí)現(xiàn)可供調(diào)用。
4.支持 okhttp、Volley。Glide 默認(rèn)通過 UrlConnection 獲取數(shù)據(jù),可以配合 okhttp 或是 Volley 使用。實(shí)際 ImageLoader、Picasso 也都支持 okhttp、Volley。
5.內(nèi)存友好。Glide 的內(nèi)存緩存有個(gè) active 的設(shè)計(jì),從內(nèi)存緩存中取數(shù)據(jù)時(shí),不像一般的實(shí)現(xiàn)用 get,而是用 remove,再將這個(gè)緩存數(shù)據(jù)放到一個(gè) value 為軟引用的 activeResources map 中,并計(jì)數(shù)引用數(shù),在圖片加載完成后進(jìn)行判斷,如果引用計(jì)數(shù)為空則回收掉。內(nèi)存緩存更小圖片,Glide 以 url、view_width、view_height、屏幕的分辨率等做為聯(lián)合 key,將處理后的圖片緩存在內(nèi)存緩存中,而不是原始圖片以節(jié)省大小與 Activity/Fragment 生命周期一致,支持 trimMemory。
圖片默認(rèn)使用默認(rèn) RGB_565 而不是 ARGB_888,雖然清晰度差些,但圖片更小,也可配置到 ARGB_888。
6.Glide 可以通過 signature 或不使用本地緩存支持 url 過期
使用步驟
1. 導(dǎo)入Glide的jar包,添加依賴
2. 加載圖片
Glide.with(mContext) //創(chuàng)建Glide
.load(data.url) //傳入路徑
.into(holder.ivIcon);//圖片加載到那個(gè)位置
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
android TabHost(選項(xiàng)卡)的使用方法
Android中的選項(xiàng)卡是用TabHost實(shí)現(xiàn)的,下面我們用一個(gè)例子說明他的使用方法2013-11-11
Android TreeView實(shí)現(xiàn)帶復(fù)選框樹形組織結(jié)構(gòu)
這篇文章主要為大家詳細(xì)介紹了Android TreeView實(shí)現(xiàn)帶復(fù)選框樹形組織結(jié)構(gòu),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
Android自定義PasswordInputView密碼輸入
這篇文章主要為大家詳細(xì)介紹了Android自定義PasswordInputView密碼輸入功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android基于PhotoView實(shí)現(xiàn)的頭像/圓形裁剪控件
這篇文章主要給大家介紹了關(guān)于Android基于PhotoView實(shí)現(xiàn)的頭像/圓形裁剪控件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
Android判斷和監(jiān)聽底座狀態(tài)和類型的方法介紹
這篇文章主要介紹了Android判斷和監(jiān)聽底座狀態(tài)和類型的方法介紹,例如判斷當(dāng)前底座狀態(tài)、判斷插入底座類型、監(jiān)控充電充電狀態(tài)等,需要的朋友可以參考下2014-06-06
Android開發(fā)之電話撥號(hào)器實(shí)例詳解
這篇文章主要介紹了Android開發(fā)之電話撥號(hào)器,結(jié)合實(shí)例形式詳細(xì)分析了Android電話撥號(hào)器的實(shí)現(xiàn)步驟與具體代碼,并附帶了一個(gè)Android開放電話撥號(hào)器的學(xué)習(xí)筆記,需要的朋友可以參考下2015-12-12
Android開發(fā)listview選中高亮簡(jiǎn)單實(shí)現(xiàn)代碼分享
這篇文章主要介紹了Android開發(fā)listview選中高亮簡(jiǎn)單實(shí)現(xiàn)代碼分享,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01

