1. 程式人生 > >圖片載入之Picasso使用

圖片載入之Picasso使用

簡介

PicassoSquare公司開源的一個Android圖形快取庫,可以實現圖片下載和快取功能。

主要有以下一些特性:

  1. Adapter中回收和取消已經不在視野範圍圖片資源的載入,防止可能出現的圖片錯位;
  2. 使用複雜的圖片壓縮轉換來儘可能的減少記憶體消耗;
  3. 使用最少的記憶體完成複雜的圖形轉換操作;
  4. 自帶記憶體和硬碟快取;
  5. 可載入網路或本地資源。

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

為請求新增標記提升使用者體驗。比如在列表ListViewItem中載入了圖片,當用戶在快速滑動的時候可以設定停止請求,在滑動停止時再去載入請求,退出當前頁面時取消請求。

Picasso提供了三種設定Tag的方式:

  1. 暫停標記:pauseTag()
  2. 可見標記:resumeTag()
  3. 取消標記: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預設的快取分配大小特點:

  1. LRU快取佔應用程式可用記憶體的15%
  2. 本地快取佔硬碟空間的2%,但不超過50M且不小於5M(前提是這種情況只在4.0以上有效果或者你能像OKHttp那樣提供一個本地快取庫來支援全平臺);
  3. Picasso預設開啟3個執行緒來進行本地與網路之間的訪問;
  4. Picasso載入圖片順序為記憶體–>本地–>網路。

22. 記憶體策略:

MemoryPolicy負責管理記憶體快取,可能有的時候你不想讓Picasso去記憶體中進行讀取而跳過此步驟,此時你可以在進行網路請求的時候呼叫memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional)方法。MemoryPolicy是一個列舉型別,只有兩個值:NO_CACHENO_STORE

  1. NO_CACHE:讓Picasso跳過從記憶體中讀取圖片這一操作;
  2. 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負責管理本地快取,它也是一個列舉型別。

  1. NO_CACHE:跳過從本地讀取資源這一過程;
  2. NO_STORE:不進行本地圖片快取;
  3. 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

這樣每張圖片在顯示的時候,左上角都會有一個小標記,分別是藍色、綠色、紅色三種顏色。

  1. 藍色:從記憶體中獲取,效能最佳;
  2. 綠色:從本地獲取,效能一般;
  3. 紅色:從網路載入,效能最差。

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-ControlExpired控制圖片的過期時間。

自定義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

GlidePicasso比較

使用方法

1、Glide更容易使用,因為Glidewith()方法不光接受Context,還能接受ActivityFragmentContext會自動從它們獲取。Picasso只接受Context
2、將Activity/Fragment作為with()引數的好處是圖片載入將會和Activity/Fragment的生命週期保持一致。比如在onPause狀態暫停載入,在onResume狀態的時候又自動重新載入。

預設Bitmap格式

1、Glide預設Bitmap格式是RGB_565Picasso預設的Bitmap格式的是ARGB_8888
2、想要提高Glide的圖片效果,Glide可以建立一個新的GlideModuleBitmap格式轉換為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 × 432ImageView中,Glide載入的圖片質量要差於Picasso。這是因為Glide預設的Bitmap格式是RGB-565,比ARGB-8888格式的記憶體開銷大約要小一半。

GIF顯示

1、Glide支援GIF顯示,而Picasso不支援GIF顯示。
2、因為GlideActivity/Fragment的生命週期是一致的,因此GIF動畫也會自動的隨Activity/Fragment的狀態而進行暫停或者重放。Glide快取在GIF這裡也是一樣,會調整大小然後快取。

快取策略

1、PicassoGlide在磁碟快取策略上有很大的不同。Picasso快取的是全尺寸的,而Glide快取的是跟ImageView尺寸相同的。
2、Picasso只快取一個全尺寸的,而Glide會為每種大小的ImageView快取一次。儘管一張圖片已經快取了一次,但是假如你要在另外一個地方再次以不同尺寸顯示時還需要重新下載,然後將其調整成新尺寸的大小快取起來。
3、具體來說就是:假如在第一個頁面有一個200 x 200ImageView,在第二個頁面有一個100 x 100ImageView,這兩個ImageView本來是要顯示同一張圖片,但是Glide卻需要下載兩次。
4、可以改變以上這種行為,讓Glide既快取全尺寸又快取其他尺寸:

Glide.with(this)
    .load(Constant.image_dynamic)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .into(ivImage);
  • 1
  • 2
  • 3
  • 4

下次在任何ImageView中載入圖片的時候,全尺寸的圖片將從快取中取出重新調整大小,然後進行快取。

5、Glide的這種快取方式優點是載入顯示非常快,而Picasso的方式則因為需要在顯示之前重新調整大小而導致一些延遲,不過GlidePicasso需要更大的空間來進行快取。

其他

1、包的大小:Picasso(v2.5.1)的大小約118kb,而Glide(v3.5.2)的大小約430kb
2、方法數目:PicassoGlide的方法個數分別是8402678個。對於DEX檔案65535個方法限制來說,2678是一個相當大的數字了。建議在使用Glide的時候開啟ProGuard
3、Glide可以將任何的本地視訊解碼成一張靜態圖片,而Picasso不可以。

Fresco優缺點

FrescoFacebook開源Android平臺上一個強大的圖片載入庫。

主要特點

  1. 兩個記憶體快取加上Native快取構成了三級快取;
  2. 支援流式,可以類似網頁上模糊漸進方式顯示圖片;
  3. 對多幀動畫圖片支援更好,如:GifWebP等。

記憶體管理

Fresco最大的亮點在於它的記憶體管理。Android中的Bitmap佔用大量的記憶體,在Android 5.0以下系統中,這會顯著地引發介面卡頓,而使用Fresco將會很好地解決這個問題。Fresco會將圖片放到一個特別的記憶體區域,當圖片不再顯示的時候,佔用的記憶體會自動被釋放。這會使得APP更加流暢,減少因圖片記憶體佔用而引發的OOM,當APP包含的圖片較多時這個效果尤其明顯。

影象

Fresco支援影象的漸進式呈現,漸進式的圖片格式先呈現大致的圖片輪廓,然後隨著圖片下載的繼續,逐漸呈現清晰的圖片。這在低網速情況下瀏覽圖片十分有幫助,可以帶來更好地使用者體驗。另外Fresco支援載入GIFWebP格式。

優點

  1. 圖片儲存在安卓系統的匿名共享記憶體,而不是虛擬機器的堆記憶體中,圖片的中間緩衝資料也存放在本地堆記憶體。所以應用程式有更多的記憶體使用,不會因為圖片載入而導致OOM,同時也減少垃圾回收器頻繁呼叫回收Bitmap導致的介面卡頓,效能更高;
  2. 漸進式載入JPEG圖片,支援圖片從模糊到清晰載入;
  3. 圖片可以以任意的中心點顯示在ImageView,而不僅僅是圖片的中心;
  4. JPEG圖片改變大小也是在native進行的,不是在虛擬機器的堆記憶體,同樣減少OOM的發生;
  5. 很好的支援GIF圖片顯示。

缺點

  1. 框架較大,影響Apk體積;
  2. 使用較繁瑣。

ImageLoader優缺點

比較老的框架、穩定、載入速度適中。

優點

  1. 多執行緒下載圖片,圖片可以來源於網路、檔案、assets以及drawable中等;
  2. 支援自定義的配置ImageLoader,例如執行緒池、圖片下載器、記憶體快取策略、硬碟快取策略、圖片顯示選項以及其他的一些配置;
  3. 支援圖片的記憶體快取、檔案系統快取或者SD卡快取;
  4. 預設實現多種記憶體快取演算法,如Size最大先刪除、使用最少先刪除、最近最少使用先刪除、先進先刪除、時間最長先刪除等;
  5. 支援圖片下載過程監聽;
  6. 根據控制元件(ImageView)的大小對Bitmap進行裁剪,減少Bitmap佔用過多的記憶體;
  7. 較好的控制圖片的載入過程,例如暫停圖片載入、重新開始載入圖片等,一般使用在ListViewGridView中,通過PauseOnScrollListener介面控制滑動過程中暫停載入圖片,停止滑動的時候去載入圖片;
  8. 提供在較慢的網路下對圖片進行載入。

缺點

不支援GIF圖片載入,使用稍微繁瑣,並且快取機制沒有和Http的快取很好的結合,完全是自己的一套快取機制。

Picasso優缺點

使用方便、一行程式碼完成載入圖片並顯示、框架體積小。

優點

  1. 自帶統計檢測功能:支援圖片快取使用檢測,包括:快取命中率、已使用記憶體大小、節省的流量等;
  2. 支援優先順序處理:每次任務排程前會選擇優先順序高的任務,比如App頁面中Banner的優先順序高於Icon時就很適用;
  3. 支援延遲到圖片尺寸計算完成載入;
  4. 支援飛航模式、併發執行緒數根據網路狀態變化:手機切換到飛航模式或網路狀態變換時會自動調整執行緒池最大併發數;
  5. “無”本地快取:無”本地快取不是說沒有本地快取,而是Picasso自己沒有實現,交給了Square的另外一個網路庫OkHttp去實現。這樣的好處是可以通過請求Response Header中的Cache-ControlExpired來控制圖片的過期時間。

缺點

不支援GIF,快取圖片是未縮放的,預設使用ARGB_8888格式快取圖片,快取體積大。

Glide優缺點

優點

  1. 圖片佔用記憶體回收及時,能減少因記憶體不足造成的崩潰,生命週期和Activity/Fragment一致;
  2. 預設Bitmap格式是RGB_565,減少記憶體資源佔用;
  3. GlideUniversal-Image-Loader佔用的記憶體要小一些;
  4. 圖片顯示效果為漸變,更加平滑;
  5. Glide可以將任何的本地視訊解碼成一張靜態圖片;
  6. 支援GifWebP、縮圖等。

缺點

框架較大,影響Apk體積。

專案地址 ☞ 傳送門