圖片載入之Picasso使用
簡介
Picasso
是Square
公司開源的一個Android
圖形快取庫,可以實現圖片下載和快取功能。
主要有以下一些特性:
- 在
Adapter
中回收和取消已經不在視野範圍圖片資源的載入,防止可能出現的圖片錯位; - 使用複雜的圖片壓縮轉換來儘可能的減少記憶體消耗;
- 使用最少的記憶體完成複雜的圖形轉換操作;
- 自帶記憶體和硬碟快取;
- 可載入網路或本地資源。
GitHub
地址:
背景
Android
系統作為圖片資源載入的主角,它是通過影象的畫素點來將影象載入到記憶體中的。現在一張500W
的攝像頭拍出的照片(2592x1936)
載入到記憶體中需要大約19M
的記憶體,如果你加入了在訊號強度不一的網路中進行復雜的網路請求,並進行圖片的快取與其他處理時,你將會耗費大量的時間與精力來處理這些問題,但如果使用Picasso
配置
build.gradle
配置:
compile 'com.squareup.picasso:picasso:2.5.2'
- 1
混淆配置:
-dontwarn com.squareup.okhttp.**
- 1
網路配置:
<uses-permissionandroid:name="android.permission.INTERNET" />
- 1
圖片載入
Picasso
使用簡單易用的介面,並有一個實現類Picasso
,一個完整的圖片載入請求至少需要三個引數:
with(Context context):
load(String path):
載入圖片的地址; into(ImageView target):
圖片展示的ImageView
。
簡單用例:
Picasso.with(mActivity)
.load(Constant.picUrl)
.into(mIvNetworkPictures);
- 1
- 2
- 3
其他載入方式:
可以載入資原始檔、本地File
檔案、Uri
地址等。
常用方法
1. .noFade()
:
Picasso
的預設圖片載入方式有一個淡入的效果,如果呼叫了noFade()
方法後加載的圖片將直接顯示在ImageView
上。
2. .noPlaceholder()
有一個場景,當你從網上載入了一張圖片到Imageview
上後,過了一段時間想在同一個ImageView
上展示另外一張圖片。這個時候你就會去呼叫Picasso
進行二次請求,這時Picasso
就會把之前的圖片進行清除,可能展示的是.placeholder()
狀態的圖片,給使用者並不是很好的體驗,如果呼叫了noPlaceholder()
方法就不會出現這種情況了。
3. .resize(int targetWidth, int targetHeight)
:
如果圖片很大或者想自定義圖片的顯示樣式時,可以使用此方法來裁剪圖片尺寸。
4. .onlyScaleDown()
:
如果呼叫了resize(width,height)
方法的話,Picasso
一般會重新計算以改變圖片的載入質量,比如一張小圖變成一張大圖進行展示的時候。但是如果我們的原圖是比重新resize
的新圖規格大的時候,我們就可以呼叫onlyScaleDown()
來直接進行展示而不再重新計算,縮短圖片的載入計算時間。
5. .centerInside()
:
圖片會被完整的展示,可能圖片不會填充滿ImageView
,也有可能會被拉伸或者擠壓,一般是等比例縮小。
6. .centerCrop()
:
圖片會被裁剪,但是圖片質量沒有什麼區別,等比例放大。
7. .fit()
:
Picasso
會對圖片的大小及ImageView
進行測量,計算出最佳的大小及最佳的圖片質量來進行圖片展示,減少記憶體的消耗並對檢視沒有影響。
8. .priority()
:
如果一個檢視中頂部圖片較大而底部圖片較小,因為Picasso
是非同步載入,所以小圖會先加載出來。但是對於使用者來說或許更希望看到的是上面的圖片先被載入而底部的圖片後被載入,此時可使用此方法來設定圖片載入的優先順序。
注意:設定優先順序並不能保證圖片就一定會被優先載入,只是會偏向傾斜於先載入。
9. .tag()
:
為請求新增標記提升使用者體驗。比如在列表ListView
的Item
中載入了圖片,當用戶在快速滑動的時候可以設定停止請求,在滑動停止時再去載入請求,退出當前頁面時取消請求。
Picasso
提供了三種設定Tag
的方式:
- 暫停標記:
pauseTag()
- 可見標記:
resumeTag()
- 取消標記:
cancelTag()
在圖片請求載入時新增標記:
Picasso.with(mActivity)
.load(Constant.picUrl)
.tag("mark")
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
ListView
實現滑動監聽OnScrollListener
:
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Picasso picasso = Picasso.with(mActivity);
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) {
picasso.resumeTag("mark");
} else {
picasso.pauseTag("mark");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
在頁面進行跳轉或者退出時取消請求:
@Override
protected void onDestroy() {
super.onDestroy();
Picasso.with(mActivity)
.cancelTag("mark");
}
- 1
- 2
- 3
- 4
- 5
- 6
注意:如果Tag
狀態為pause
或者resume
的時候,Picasso
會對Tag
持有一個引用,如果此時使用者退出了當前Activity
,垃圾回收機制進行回收的時候就可能會出現記憶體洩露,所以需要在onDestroy()
方法中進行相應處理。
10. .fetch()
:
該方法會在後臺非同步載入一張圖片,但是不會展示在ImageView
上,也不會返回Bitmap
,這個方法只是為了將獲取到的資源載入到本地和記憶體當中,為後期的載入縮短時間。
11. .get()
:
該方法是一個非同步執行緒,載入完成後會返回一個Bitmap
,但是需要注意的是該方法不能在主執行緒中呼叫,因為會造成執行緒阻塞。
12. Target
:
之前呼叫into()
方法是將獲取到的資源載入到ImageView
中,但我們還可以將資源作為回撥放到Target
中。
private Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
//然後進行呼叫即可
Picasso.with(mActivity)
.load(Constant.picUrl)
.into(target);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
注意:可以使用.get()
或者Target
獲取圖片的Bitmap
,但是當你使用Target
時不能使用匿名內部類的方式,因為垃圾回收機制在你獲取不到Bitmap
的時候會把物件回收。
13. .rotate(float degrees)
:
當我們需要對一張圖片進行簡單旋轉處理時,只需要傳入大於0
小於360
的旋轉角度即可。
14. .rotate(float degrees, float pivotX, float pivotY)
:
預設的圖片旋轉都是相對(0,0)
進行旋轉的,所以如果我們想自定義相對於某個點的旋轉時可以呼叫以上方法。
15. .error
:
載入失敗時的圖片顯示,如果重試3
次(下載原始碼可以根據需要修改)還是無法成功載入圖片,則用錯誤佔位符圖片顯示。
16. .placeholder()
:
載入過程中的圖片顯示。
17. 如果圖片地址不存在或為空的時候怎麼處理?
當圖片地址不存在或為空時,可以先呼叫cancelRequest()
方法取消網路請求,然後呼叫imageView.setImageDrawable(null)
方法進行設定。
if (StringUtil.isEmpty(Constant.picUrl)) {
Picasso.with(mActivity)
.cancelRequest(mIvNetworkPictures);
mIvNetworkPictures.setImageDrawable(null);
}
- 1
- 2
- 3
- 4
- 5
18. Picasso
在自定義Notification
中的使用:
Picasso
有一個功能是可以載入圖片到RemoteViews
上,而RemoteViews
是用在Widget
及自定義Notification
佈局中的,以下是其使用方式。
Picasso.with(mActivity)
.load(Constant.picUrl)
.into(remoteViews, R.id.iv_remoteView, notificationId, notification);
- 1
- 2
- 3
19. 模糊圖片:
我們可以在圖片進行展示之前對其進行配置後在展示,這時我們需要定義一個類實現Transformation
介面,然後重寫裡面的方法。
private classBlurTransformationimplementsTransformation {
RenderScript rs;
public BlurTransformation(Context context) {
rs = RenderScript.create(context);
}
@Override
public Bitmap transform(Bitmap bitmap) {
// 建立一個Bitmap作為最後處理的效果Bitmap
Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
// 分配記憶體
Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
Allocation output = Allocation.createTyped(rs, input.getType());
// 根據我們想使用的配置載入一個例項
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
// 設定模糊半徑
script.setRadius(10);
//開始操作
script.forEach(output);
// 將結果copy到blurredBitmap中
output.copyTo(blurredBitmap);
//釋放資源
bitmap.recycle();
return blurredBitmap;
}
@Override
public String key() {
return "blur";
}
}
//然後進行呼叫即可
Picasso.with(mActivity)
.load(Constant.picUrl)
.transform(new BlurTransformation(mActivity))
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
20. 模糊+圓形:
Picasso
給我們提供了一個這樣的API
,允許我們將引數設定為一個Transformations
的集合transform(List<? extends Transformation> transformations)
,這就意味著我們可以對載入的資源進行一系列的操作。
private classCircleTransformationimplementsTransformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circle";
}
}
//然後進行呼叫即可
List<Transformation> transformations = new ArrayList<>();
transformations.add(new CircleTransformation());
transformations.add(new BlurTransformation(mActivity));
Picasso.with(mActivity)
.load(Constant.picUrl)
.transform(transformations)
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
21. 快取機制:
Picasso
預設的快取分配大小特點:
LRU
快取佔應用程式可用記憶體的15%
;- 本地快取佔硬碟空間的
2%
,但不超過50M
且不小於5M
(前提是這種情況只在4.0
以上有效果或者你能像OKHttp
那樣提供一個本地快取庫來支援全平臺); Picasso
預設開啟3
個執行緒來進行本地與網路之間的訪問;Picasso
載入圖片順序為記憶體–>本地–>網路。
22. 記憶體策略:
MemoryPolicy
負責管理記憶體快取,可能有的時候你不想讓Picasso
去記憶體中進行讀取而跳過此步驟,此時你可以在進行網路請求的時候呼叫memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional)
方法。MemoryPolicy
是一個列舉型別,只有兩個值:NO_CACHE
和NO_STORE
。
NO_CACHE
:讓Picasso
跳過從記憶體中讀取圖片這一操作;NO_STORE
:如果你的圖片只加載一次就不在使用了就可以設定該值,這樣的話Picasso
就不會在記憶體及本地進行快取了。
程式碼示例:
Picasso.with(mActivity)
.load(Constant.picUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE)
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
當然你也可以這樣呼叫:
Picasso.with(mActivity)
.load(Constant.picUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
注意:呼叫memoryPolicy(MemoryPolicy.NO_CACHE)
雖然能避免Picasso
從記憶體中讀取資源,但是並不能避免從本地讀取資源。
23. 網路策略:
NetworkPolicy
負責管理本地快取,它也是一個列舉型別。
NO_CACHE
:跳過從本地讀取資源這一過程;NO_STORE
:不進行本地圖片快取;OFFLINE
:載入圖片的時候只從本地讀取,除非網路正常且本地找不到資源的情況下。
示例程式碼:
Picasso.with(mActivity)
.load(Constant.picUrl)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
24. 快取指示器,檢視圖片來源於何處:
當我們想知道所載入的圖片來源於何處,是記憶體、本地還是從網路載入的時候,只需要在請求的時候呼叫.setIndicatorsEnabled(true)
方法就好了。
Picasso.with(mActivity)
.setIndicatorsEnabled(true);
- 1
- 2
這樣每張圖片在顯示的時候,左上角都會有一個小標記,分別是藍色、綠色、紅色三種顏色。
- 藍色:從記憶體中獲取,效能最佳;
- 綠色:從本地獲取,效能一般;
- 紅色:從網路載入,效能最差。
25. 檢視圖片載入用時:
在圖片載入請求開始前呼叫.setLoggingEnabled(true)
方法,通過輸出日誌的方式檢視每張圖片從網路請求載入時用的時間。
Picasso.with(mActivity)
.setLoggingEnabled(true);
Picasso.with(mActivity)
.load(Constant.picUrl)
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
- 5
- 6
然後在控制檯上檢視日誌資訊如下:
D/Picasso: Main created [R0] Request{http://img.taopic.com/uploads/allimg/131009/235013-13100ZP54561.jpg}
D/Picasso: Dispatcher enqueued [R0]+8ms
D/Picasso: Hunter executing [R0]+9ms
D/Picasso: Hunter decoded [R0]+46ms
D/Picasso: Dispatcher batched [R0]+47ms for completion
D/Picasso: Dispatcher delivered [R0]+248ms
D/Picasso: Main completed [R0]+249ms from DISK
- 1
- 2
- 3
- 4
- 5
- 6
- 7
26. 圖片載入分析:
檢視圖片的載入在記憶體中佔用了多大可以呼叫StatsSnapshot
即可。
StatsSnapshot statsSnapshot = Picasso.with(mActivity).getSnapshot();
LogUtil.e(Constant.LOG_TAG, "statsSnapshot:" + statsSnapshot.toString());
- 1
- 2
最後輸出結果為:
statsSnapshot:StatsSnapshot{maxSize=19173961, size=0, cacheHits=0, cacheMisses=1, downloadCount=0, totalDownloadSize=0, averageDownloadSize=0, totalOriginalBitmapSize=0, totalTransformedBitmapSize=0, averageOriginalBitmapSize=0, averageTransformedBitmapSize=0, originalBitmapCount=0, transformedBitmapCount=0, timeStamp=1494484266351}
- 1
27. 建立一個Picasso
:
Picasso
有一個直接的方法去建立一個它的例項,就是Picasso.Builder
類,這樣就可以建立屬於我們自己的Picasso
,而不是使用一個標準的Picasso
。
Picasso picasso = new Picasso.Builder(mActivity).build();
- 1
28. 標準建立方式:
我們最常用的就是直接呼叫Picasso.with(context)
返回一個Picasso
例項,這就是一個標準的Picasso
。
Picasso picasso = Picasso.with(mActivity);
- 1
29. 自定義建立Picasso例項:
呼叫Picasso.Builder
建立的例項就是我們自定義的Picasso
,當然它也預設實現了標準Picasso
的所有功能,我們也可以像用標準的Picasso
一樣進行使用。
Picasso.Builder pb = new Picasso.Builder(mActivity);
Picasso picasso = pb.build();
picasso.load(Constant.picUrl)
.into(mIvNetworkPictures);
- 1
- 2
- 3
- 4
30. 將自定義Picasso
變成全域性使用:
在應用啟動的時候呼叫Picasso.setSingletonInstance(picasso)
方法,這樣的話後面所有呼叫Picasso.with(context)
返回的都是我們自定義的Picasso
。
Picasso.Builder pb = new Picasso.Builder(mActivity);
Picasso picasso = pb.build();
Picasso.setSingletonInstance(picasso);
- 1
- 2
- 3
31. 支援飛航模式,併發執行緒數可根據網路狀態改變:
手機切換到飛航模式或網路狀態改變時會自動調整執行緒池的最大併發數,預設執行緒數為3
個執行緒,wifi
狀態下為4
個執行緒,4G
狀態下為3
個執行緒,3G
狀態下為2
個執行緒,2G
狀態下為1
個執行緒。
32. “無”本地快取:
“無”本地快取不是說沒有本地快取,而是Picasso
自己沒有實現,交給了Square
的另外一個網路庫OKHttp
去實現。這樣的好處是可以通過請求Response Header
中的Cache-Control
及Expired
控制圖片的過期時間。
自定義Picasso
快取
Picasso
預設的快取路徑位於data/data/your package name/cache/picasso-cache/
下。開發過程中我們難免會遇到一些需求,需要我們去修改圖片的快取路徑。
分析:
我們注意到Picasso
底層其實是使用OkHttp
去下載圖片,同時在設定Picasso
的時候有一個.downloader(Downloader downloader)
方法,我們可以傳遞進去一個OkHttpDownloader(...)
。
實現:
1.方法一
OkHttp
依賴
compile 'com.squareup.okhttp:okhttp:2.4.0'
- 1
自定義快取目錄
FileUtil.getCachePath(mContext)
- 1
自定義建立Picasso
例項並應用到全域性
Picasso.Builder pb = new Picasso.Builder(this);
Picasso picasso = pb
.downloader(new OkHttpDownloader(new File(FileUtil.getCachePath(this))))
.build();
Picasso.setSingletonInstance(picasso);
- 1
- 2
- 3
- 4
- 5
2.方法二
當你把OkHttp
升級到OkHttp3
的時候,你會發現給downloader
設定OkHttpDownloader()
的時候,發現它並不支援OkHttp3
。為了解決不能使用OkHttp3
作為下載器的問題,Picasso
作者jakewharton
大神專門寫了一個OkHttp3Downloader
庫。使用也非常簡單,在專案build.gradle
中新增依賴:
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
- 1
然後設定downloader
的時候改為OkHttp3Downloader
即可。
自定義快取目錄和快取大小
// 設定快取目錄
File directory = new File(FileUtil.getCachePath(this));
if (!directory.exists()) {
directory.mkdirs();
}
// 設定快取大小為執行時快取的八分之一
long maxSize = Runtime.getRuntime().maxMemory() / 8;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
自定義建立Picasso
例項並應用到全域性
OkHttpClient client = new OkHttpClient.Builder()
.cache(new Cache(directory, maxSize))
.build();
Picasso picasso = new Picasso.Builder(this)
.downloader(new OkHttp3Downloader(client))
.build();
Picasso.setSingletonInstance(picasso);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Glide
與Picasso
比較
使用方法
1、Glide
更容易使用,因為Glide
的with()
方法不光接受Context
,還能接受Activity
和Fragment
,Context
會自動從它們獲取。Picasso
只接受Context
。
2、將Activity/Fragment
作為with()
引數的好處是圖片載入將會和Activity/Fragment
的生命週期保持一致。比如在onPause
狀態暫停載入,在onResume
狀態的時候又自動重新載入。
預設Bitmap
格式
1、Glide
預設Bitmap
格式是RGB_565
,Picasso
預設的Bitmap
格式的是ARGB_8888
。
2、想要提高Glide
的圖片效果,Glide
可以建立一個新的GlideModule
將Bitmap
格式轉換為ARGB_8888
:
public classGlideConfigurationimplementsGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
同時在AndroidManifest.xml
中將GlideModule
定義為meta-data
。
<meta-data
android:name="com.wiggins.glide.GlideConfiguration"
android:value="GlideModule" />
- 1
- 2
- 3
載入策略
1、Picasso
是載入了全尺寸的圖片到記憶體,然後讓GPU
來實時重繪大小。而Glide
載入的大小和ImageView
的大小是一致的,因此會更小。
2、Picasso
也可以指定載入的圖片大小:
Picasso.with(mActivity)
.load(Constant.picUrl)
.resize(768, 432)
.into(mIvPic);
- 1
- 2
- 3
- 4
但是問題在於你需要主動計算ImageView
的大小,或者說你的ImageView
大小是具體的值(而不是wrap_content
),你也可以這樣:
Picasso.with(mActivity)
.load(Constant.picUrl)
.fit()
.centerCrop()
.into(mIvPic);
- 1
- 2
- 3
- 4
- 5
Image
質量細節
將ImageView
還原到真實大小時,Glide
載入的圖片沒有Picasso
那麼平滑。
影象和記憶體
同樣將1080 × 1920
畫素的圖片載入到768 × 432
的ImageView
中,Glide
載入的圖片質量要差於Picasso
。這是因為Glide
預設的Bitmap
格式是RGB-565
,比ARGB-8888
格式的記憶體開銷大約要小一半。
GIF
顯示
1、Glide
支援GIF
顯示,而Picasso
不支援GIF
顯示。
2、因為Glide
和Activity/Fragment
的生命週期是一致的,因此GIF
動畫也會自動的隨Activity/Fragment
的狀態而進行暫停或者重放。Glide
快取在GIF
這裡也是一樣,會調整大小然後快取。
快取策略
1、Picasso
和Glide
在磁碟快取策略上有很大的不同。Picasso
快取的是全尺寸的,而Glide
快取的是跟ImageView
尺寸相同的。
2、Picasso
只快取一個全尺寸的,而Glide
會為每種大小的ImageView
快取一次。儘管一張圖片已經快取了一次,但是假如你要在另外一個地方再次以不同尺寸顯示時還需要重新下載,然後將其調整成新尺寸的大小快取起來。
3、具體來說就是:假如在第一個頁面有一個200 x 200
的ImageView
,在第二個頁面有一個100 x 100
的ImageView
,這兩個ImageView
本來是要顯示同一張圖片,但是Glide
卻需要下載兩次。
4、可以改變以上這種行為,讓Glide
既快取全尺寸又快取其他尺寸:
Glide.with(this)
.load(Constant.image_dynamic)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivImage);
- 1
- 2
- 3
- 4
下次在任何ImageView
中載入圖片的時候,全尺寸的圖片將從快取中取出重新調整大小,然後進行快取。
5、Glide
的這種快取方式優點是載入顯示非常快,而Picasso
的方式則因為需要在顯示之前重新調整大小而導致一些延遲,不過Glide
比Picasso
需要更大的空間來進行快取。
其他
1、包的大小:Picasso(v2.5.1)
的大小約118kb
,而Glide(v3.5.2)
的大小約430kb
。
2、方法數目:Picasso
和Glide
的方法個數分別是840
和2678
個。對於DEX
檔案65535
個方法限制來說,2678
是一個相當大的數字了。建議在使用Glide
的時候開啟ProGuard
。
3、Glide
可以將任何的本地視訊解碼成一張靜態圖片,而Picasso
不可以。
Fresco
優缺點
Fresco
是Facebook
開源Android
平臺上一個強大的圖片載入庫。
主要特點
- 兩個記憶體快取加上
Native
快取構成了三級快取; - 支援流式,可以類似網頁上模糊漸進方式顯示圖片;
- 對多幀動畫圖片支援更好,如:
Gif
、WebP
等。
記憶體管理
Fresco
最大的亮點在於它的記憶體管理。Android
中的Bitmap
佔用大量的記憶體,在Android 5.0
以下系統中,這會顯著地引發介面卡頓,而使用Fresco
將會很好地解決這個問題。Fresco
會將圖片放到一個特別的記憶體區域,當圖片不再顯示的時候,佔用的記憶體會自動被釋放。這會使得APP
更加流暢,減少因圖片記憶體佔用而引發的OOM
,當APP
包含的圖片較多時這個效果尤其明顯。
影象
Fresco
支援影象的漸進式呈現,漸進式的圖片格式先呈現大致的圖片輪廓,然後隨著圖片下載的繼續,逐漸呈現清晰的圖片。這在低網速情況下瀏覽圖片十分有幫助,可以帶來更好地使用者體驗。另外Fresco
支援載入GIF
、WebP
格式。
優點
- 圖片儲存在安卓系統的匿名共享記憶體,而不是虛擬機器的堆記憶體中,圖片的中間緩衝資料也存放在本地堆記憶體。所以應用程式有更多的記憶體使用,不會因為圖片載入而導致
OOM
,同時也減少垃圾回收器頻繁呼叫回收Bitmap
導致的介面卡頓,效能更高; - 漸進式載入
JPEG
圖片,支援圖片從模糊到清晰載入; - 圖片可以以任意的中心點顯示在
ImageView
,而不僅僅是圖片的中心; JPEG
圖片改變大小也是在native
進行的,不是在虛擬機器的堆記憶體,同樣減少OOM
的發生;- 很好的支援
GIF
圖片顯示。
缺點
- 框架較大,影響
Apk
體積; - 使用較繁瑣。
ImageLoader
優缺點
比較老的框架、穩定、載入速度適中。
優點
- 多執行緒下載圖片,圖片可以來源於網路、檔案、
assets
以及drawable
中等; - 支援自定義的配置
ImageLoader
,例如執行緒池、圖片下載器、記憶體快取策略、硬碟快取策略、圖片顯示選項以及其他的一些配置; - 支援圖片的記憶體快取、檔案系統快取或者
SD
卡快取; - 預設實現多種記憶體快取演算法,如
Size
最大先刪除、使用最少先刪除、最近最少使用先刪除、先進先刪除、時間最長先刪除等; - 支援圖片下載過程監聽;
- 根據控制元件
(ImageView)
的大小對Bitmap
進行裁剪,減少Bitmap
佔用過多的記憶體; - 較好的控制圖片的載入過程,例如暫停圖片載入、重新開始載入圖片等,一般使用在
ListView
、GridView
中,通過PauseOnScrollListener
介面控制滑動過程中暫停載入圖片,停止滑動的時候去載入圖片; - 提供在較慢的網路下對圖片進行載入。
缺點
不支援GIF
圖片載入,使用稍微繁瑣,並且快取機制沒有和Http
的快取很好的結合,完全是自己的一套快取機制。
Picasso
優缺點
使用方便、一行程式碼完成載入圖片並顯示、框架體積小。
優點
- 自帶統計檢測功能:支援圖片快取使用檢測,包括:快取命中率、已使用記憶體大小、節省的流量等;
- 支援優先順序處理:每次任務排程前會選擇優先順序高的任務,比如
App
頁面中Banner
的優先順序高於Icon
時就很適用; - 支援延遲到圖片尺寸計算完成載入;
- 支援飛航模式、併發執行緒數根據網路狀態變化:手機切換到飛航模式或網路狀態變換時會自動調整執行緒池最大併發數;
- “無”本地快取:無”本地快取不是說沒有本地快取,而是
Picasso
自己沒有實現,交給了Square
的另外一個網路庫OkHttp
去實現。這樣的好處是可以通過請求Response Header
中的Cache-Control
及Expired
來控制圖片的過期時間。
缺點
不支援GIF
,快取圖片是未縮放的,預設使用ARGB_8888
格式快取圖片,快取體積大。
Glide
優缺點
優點
- 圖片佔用記憶體回收及時,能減少因記憶體不足造成的崩潰,生命週期和
Activity/Fragment
一致; - 預設
Bitmap
格式是RGB_565
,減少記憶體資源佔用; Glide
比Universal-Image-Loader
佔用的記憶體要小一些;- 圖片顯示效果為漸變,更加平滑;
Glide
可以將任何的本地視訊解碼成一張靜態圖片;- 支援
Gif
、WebP
、縮圖等。
缺點
框架較大,影響Apk
體積。
專案地址 ☞ 傳送門