Glide原理

1、基礎知識

如何把圖片解析成Bitmap:當ImageView可展示的像素點小於圖片的像素點,這時我們就需要壓縮圖片,避免浪費內存空間。BitmapFactory類提供了多個解析方法(decodeByteArray, decodeFile, decodeResource等)用於創建Bitmap對象,而且每一種解析方法都提供了一個可選的BitmapFactory.Options參數,將這個參數的inJustDecodeBounds屬性設置爲true就可以讓解析方法禁止爲bitmap分配內存,返回值也不再是一個Bitmap對象,而是null。雖然Bitmap是null,但是BitmapFactory.Options的outWidth、outHeight和outMimeType屬性都會被賦值,在計算壓縮比例時,我們要考慮加載控件的大小和屏幕的大小,通過設置BitmapFactory.Options中inSampleSize的值就可以壓縮圖片

圖片縮放:ScaleType分爲三個類型:以FIT_開頭的四種,共同點都是會對圖片進行縮放;以CENTER_開頭的三種,共同點是圖片的中心會與ImageView的中心點重疊;還有一種是ScaleType.MATRIX

ScaleType.FIT_CENTER:圖片會被等比例縮放到能完全展示出來,並居中顯示,圖片默認顯示模式

ScaleType.FIT_START:圖片會被等比例縮放到能完全展示出來,對齊方式爲左上角

ScaleType.FIT_END:圖片會被等比例縮放到能完全展示出來,對齊方式爲右下角

ScaleType.FIT_XY:非等比例縮放,完全填充控件大小

ScaleType.CENTER:不使用縮放,居中顯示

ScaleType.CENTER_CROP:等比例縮放至完全填充整個ImageView,並居中顯示,小圖片不進行縮放

ScaleType.CENTER_INSIDE:等比例縮放至完全展示出整個圖片,並居中顯示,小圖片不進行縮放

ScaleType.MATRIX:忽略

2、Glide簡介

dependencies {
    compile 'com.github.bumptech.glide:glide:3.5.2' 
    compile 'com.android.support:support-v4:22.0.0'
}
Glide.with(context).load("http://inthecheesefactory.com/uploads/cover.jpg").into(ivImg);

與Picasso相比,Glide的with方法不僅接收Context,還接收Activity和Fragment,同時圖片加載和Activity、Fragment的生命週期保持一致,比如在Paused狀態暫停加載,在Resumed的時候自動重新加載

Glide默認Bitmap格式是RGB_565,Picasso默認Bitmap格式是ARGB_8888

Glide內存開銷小於Picasso,原因是Picasso加載了全尺寸的圖片到內存,然後讓GPU來實時重繪大小,而Glide加載的大小和ImageView的大小是一致的,當然,Picasso也可以指定加載的圖片大小:

Picasso.with(this).load("http://nuuneoi.com/cover.jpg").resize(768, 432).into(ivImgPicasso);

但問題在於我們需要計算ImageView的大小,或者說ImageView大小是具體的值(而不是wrap_content),我們也可以這樣:

Picasso.with(this).load("http://nuuneoi.com/cover.jpg").fit().into(ivImgPicasso);

Picasso和Glide在磁盤緩存策略上有很大的不同。Picasso緩存的是全尺寸的,而Glide緩存的是跟ImageView尺寸相同的,具體說來就是:假如在第一個頁面有一個200x200的ImageView,在第二個頁面有一個100x100的ImageView,這兩個ImageView本來是要顯示同一張圖片,卻需要下載兩次,不過,你可以改變這種行爲,讓Glide既緩存全尺寸又緩存其他尺寸:

Glide.with(this).load("http://nuuneoi.com/cover.jpg").diskCacheStrategy(DiskCacheStrategy.ALL).into(ivImg);

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

Glide的這種方式優點是加載顯示非常快,而Picasso的方式則因爲需要在顯示之前重新調整大小而導致一些延遲

Glide可以加載GIF動態圖,而Picasso不能,但是從我的一次測試結果來看Glide 動畫會消費太多的內存,因此謹慎使用

3、Glide原理:

with方法:with有很多重載方法,接收參數包括Context、Actitity、FragmentActivity、Fragment等,with方法內部主要處理生命週期相關,並返回RequestManager,我們重點分析生命週期:對於ApplicationContext,直接聲明ApplicationLifecycle,並把RequestManager加入到Lifecycle的listener中,其實ApplicationLifeCycle什麼都沒做,甚至沒有存儲listeners。對於Activity和Fragment,Glide自動創建了一個Fragment,並把Fragment加入到了Activity中,並把RequestManager加入到Fragment控制的LifeCycle中,因爲Fragment的生命週期和Activity是同步的,如果Activity被銷燬了,Fragment是可以監聽到的,這樣Glide就可以捕獲這個事件並停止圖片加載了

load方法:該方法返回一個DrawableTypeRequest對象,父類是GenericRequestBuilder,裏面包括Glide絕大多數API,比如說placeholder、error、diskCacheStrategy等

into方法:主要處理流程都在into中,我們重點分析緩存策略:首先,生成緩存Key的參數有10多個(包括id、width、height等)。在內存緩存策略中,我們通過弱引用來緩存正在使用的圖片,通過LruCache(Least Recently Used)來緩存不在使用的圖片。在硬盤緩存策略中,緩存分爲兩級,首先我們通過key值訪問轉換後的結果(RESULT),如果不存在,再通過簡化的key值訪問原始圖片(SOURCE)

4、Picasso、Glide、Fresco對比

Picasso不能加載Gif圖片、只能緩存全尺寸的圖片,加載效率低、包體積小(100K)

Glide支持生命週期管理、自動裁剪圖片、三級緩存、Gif圖加載、包體積適中(500K)

Fresco支持5.0一下Ashmem區存儲、包體積大(2M)

Fresco在5.0以前使用inPurgeable選項來解碼Bitmap,這樣解碼出來的Bitmap是在Ashmem內存中,GC無法自動回收它。當該Bitmap在被使用時會被pin住,使用完之後就unpin ,這樣系統就可以在將來某一時間釋放這部分內存。如果一個unpinned的bitmap在之後又要被使用,系統會運行時又將它重新decode,但是這個decode操作是發生在UI線程中的有可能會造成掉幀現象,因此該做法已經被Google廢棄掉,轉爲鼓勵使用inBitmap來告知

爲了讓inPurgeable的bitmap不被自動unpinned,可以通過使用 jni 函數AndroidBitmap_lockPixels()函數來強制pin bitmap,這樣我們就可以在bitmap被使用時不會被系統自動unpinned,從而也就避免了unpinned 的 bitmap在重新被使用時又會被重新decode而引起的掉幀問題。這做後,Fresco需要自己去管理這塊內存區域,保證當這個Bitmap不再使用時,Ashmem的內存空間能被 unpin,Fresco選擇在Bitmap離開屏幕可視範圍時候(onDetachWindow等時候),通過調用bitmap.recycle()方法去做unpin

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章