Glide加載圖片原理----轉載


             以前項目上用的是Volley的ImageViewRequest進行圖片加載的。可后來隨着的項目的精細化,我覺得將圖片請求和json的數據請求分離使用這樣會更好。在網上查了很多資料,也進行了實踐比較。我選擇了okHhttp+Glide作為網絡請求的方式在項目上。

       okHttp我會在以后文章介紹,今天只要看看Glide用法與原理分析。這些都是我在網上整理的,大家如果要看原創,這是網址Google推薦的圖片加載庫Glide介紹

       Glide是谷歌為我們介紹了一個圖片加載庫,作者是bumptech。這個庫被廣泛的運用在google的開源項目中,包括2014年google I/O大會上發布的官方app。 它的使用比較方便。需要V4包的支持。導入Glide架包即可。


Glide.with(context)
.load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
.into(ImageView);
這里的Context可以是Activity,Fragment等。它默認的Bitmap的格式RGB_565,同時他還可以指定圖片大小;默認使用HttpUrlConnection下載圖片,可以配置為OkHttp或者Volley下載,也可以自定義下載方式。

        Glide支持圖片磁盤緩存,默認是內部存儲。Glide緩存的是跟ImageView尺寸相同的。

    Glide.with(this)  
.load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivImgGlide);
這樣不僅可以緩存ImageView大小尺寸還可以緩存其他尺寸。下次再加載ImageView的圖片時,全尺寸的圖片將會從緩存中取出,重新調整大小,然后再次緩存。這樣加載圖片顯示會很快。

        下來我想說Glide的原理。具體可以查看Glide圖片加載器詳解

     1.Glide的資源獲取組件:

  • Model: 原始資源,比如Url,AndroidResourceId, File等
  • Data: 中間資源,比如Stream,ParcelFileDescriptor(ContentProvider共享文件時比較常用,其實就是操作系統的文件描述符的封裝,里面有in out err三個取值。也有人說是鏈接建立好之后的socket句柄。)等
  • Resource:直接使用的資源,包括Bitmap,Drawable等

      2.Glide庫的資源復用:

  • Android的內存申請幾乎都在new的時候發生,而new較大對象(比如Bitmap時),更加容易觸發GC_FOR_ALLOW。所以Glide盡量的復用資源來防止不必要的GC_FOR_ALLOC引起卡頓。
  • 最顯著的內存復用就是內存LruResourceCache(第一次從網絡或者磁盤上讀取到Resource時,並不會保存到LruCache當中,當Resource被release時,也就是View不在需要此Resource時,才會進入LruCache當中)
  • 還有BitmapPool(Glide會盡量用圖片池來獲取到可以復用的圖片,獲取不到才會new,而當LruCache觸發Evicted時會把從LruCache中淘汰下來的Bitmap回收,也會把transform時用到的中間Bitmap加以復用及回收)
     3.Glide庫圖片池:

  • 4.4以前是Bitmap復用必須長寬相等才可以復用
  • 4.4及以后是Size>=所需就可以復用,只不過需要調用reconfigure來調整尺寸
  • Glide用AttributeStategy和SizeStrategy來實現兩種策略
  • 圖片池在收到傳來的Bitmap之后,通過長寬或者Size來從KeyPool中獲取Key(對象復用到了極致,連Key都用到了Pool),然后再每個Key對應一個雙向鏈表結構來存儲。每個Key下可能有很多個待用Bitmap
  • 取出后要減少圖片池中記錄的當前Size等,並對Bitmap進行eraseColor(Color.TRANSPAENT)操作確保可用
    4.Glide加載發起流程:
  1. Glide.with(context)創建RequestManager
    • RequestManager負責管理當前context的所有Request
    • Context可以傳Fragment、Activity或者其他Context,當傳Fragment、Activity時,當前頁面對應的Activity的生命周期可以被RequestManager監控到,從而可以控制Request的pause、resume、clear。這其中采用的監控方法就是在當前activity中添加一個沒有view的fragment,這樣在activity發生onStart onStop onDestroy的時候,會觸發此fragment的onStart onStop onDestroy。
    • RequestManager用來跟蹤眾多當前頁面的Request的是RequestTracker類,用弱引用來保存運行中的Request,用強引用來保存暫停需要恢復的Request。
  2. Glide.with(context).load(url)創建需要的Request
    • 通常是DrawableTypeRequest,后面可以添加transform、fitCenter、animate、placeholder、error、override、skipMemoryCache、signature等等
    • 如果需要進行Resource的轉化比如轉化為Byte數組等需要,可以加asBitmap來更改為BitmapTypeRequest
    • Request是Glide加載圖片的執行單位
  3. Glide.with(context).load(url).into(imageview)
    • 在Request的into方法中會調用Request的begin方法開始執行
    • 在正式生成EngineJob放入Engine中執行之前,如果並沒有事先調用override(width, height)來指定所需要寬高,Glide則會嘗試去獲取imageview的寬和高,如果當前imageview並沒有初始化完畢取不到高寬,Glide會通過view的ViewTreeObserver來等View初始化完畢之后再獲取寬高再進行下一步
     5.Glide加載資源:

  • GlideBuilder在初始化Glide時,會生成一個執行機Engine
  • Engine中包含LruCache緩存及一個當前正在使用的active資源Cache(弱引用)
  • activeCache輔助LruCache,當Resource從LruCache中取出使用時,會從LruCache中remove並進入acticeCache當中
  • Cache優先級LruCache>activeCache
  • Engine在初始化時要傳入兩個ExecutorService,即會有兩個線程池,一個用來從DiskCache獲取resource,另一個用來從Source中獲取(通常是下載)
  • 線程的封裝單位是EngineJob,有兩個順序狀態,先是CacheState,在此狀態先進入DiskCacheService中執行獲取,如果沒找到則進入SourceState,進到SourceService中執行下載
      6.Glide的Target:

         負責圖片加載的回調

    總結

  • Glide庫在使用過程中表現較好,滑動流暢,內存占用低
  • 代碼擴展性極強,4.0版本更加如此,但來的問題就是過於復雜,不太便於閱讀
  • 但仍會遇到有些需求Glide無法滿足
    1. 設置加載圖片的最大寬高
    2. PlaceHolder的圖片形狀不與加載的Bitmap相同會產生的抖動問題
    3. 無法指定刪除某一個圖片緩存的問題(可以用加signature的方式試其失效並重新下載,但不可以刪除)
        在網上我還看到有Picasso的圖片加載框架。其實和Glide用法很相似。



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com