Glide框架解析

Glide框架解析

Glide框架基本使用

Glide框架原理

1. with()

Glide爲何不能在子線程中with?java

子線程中不會去添加 生命週期管理機制,主線程纔會添加一個 空白的Fragment去監聽 Activity Fragment的變化。git

每個with()方法重載的代碼都很是簡單,都是調用調用getRetriever(activity).get(activity),返回一個RequestManager對象。github

getRetriever(...).get(...)作了什麼事情?算法

不論傳入Activity、FragmentActivity、Fragment最終都會調用supportFragmentGet()方法,而這兩個方法最終流程都是一致的就是那就是會向當前的Activity當中添加一個隱藏的Fragment。sql

那麼這裏爲何要添加一個隱藏的Fragment呢?緩存

答:由於Glide須要知道加載的生命週期。很簡單的一個道理,若是你在某個Activity上正在加載着一張圖片,結果圖片還沒加載出來,這時候Activity被用戶關掉了,那麼圖片就應該取消加載,但是Glide並不知道Activity的生命週期,怎麼辦呢? 因而Glide就使用了添加隱藏Fragment的這種小技巧,由於Fragment的生命週期和Activity是同步的,若是Activity被銷燬了,Fragment是能夠監聽到的,這樣Glide就能夠捕獲這個事件並中止圖片加載了。安全

既然有了Application,爲何不用registerActivityLifecycleCallbacks而是用隱藏的Fragment?markdown

registerActivityLifecycleCallbacks是能夠實現,而且個人小夥伴在本身的某些工程中也在使用,可是我的理解是這樣的: registerActivityLifecycleCallbacks監控全部的Activity生命週期,然而當你使用Glide加載圖片時,並非全部的Activity都會用到Glide加載圖片(大多數狀況),因此呢,使用registerActivityLifecycleCallbacks存在資源浪費的現象。不只如此,你監控了全部的activity怎麼和Glide想要監控的Activity關聯到一塊去,雖然能夠實現,可是這個辦法真心不實用,既然Glide給了咱們這麼完美的解決方案咱們就要學以至用,之後盡力用到本身的工程中去。網絡

2.load()

咱們能夠知道.with()方法返回的是GlideRequests對象,GlideRequests是繼承自RequestManager(負責管理和請求Glide的請求類),框架

返回 RequestBuilder 對象

3.into()

  1. 獲得ImageViewTarget 顯示圖片的地方
return into(
    // 獲得ImageViewTarget 顯示圖片的地方
    glideContext.buildImageViewTarget(view, transcodeClass));
複製代碼
  1. 構建一個請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
複製代碼

Glide問題

www.jianshu.com/p/812558735…

1. Glide加載一個100x100的圖片,是否會壓縮後再加載?放到一個300x300的view上會怎樣?

當咱們調整ImageView大小事,Glide會爲每一個不一樣尺寸的ImageView緩存一張圖片,也就是說無論你的這張圖片有沒有被加載過,只要ImageView的尺寸不同,那麼GLide就會從新加載一次,這時候,他會在加載ImageView以前從網絡上從新下載,而後再緩存。 舉個例子,若是一個頁面的ImageView是300 * 300像素,而另外一個頁面中的ImageView是100 * 100像素,這時候想要讓兩個ImageView是同一張圖片,那麼Glide須要下載兩次圖片,而且緩存兩張圖片。

2.三級緩存原理

當 Android 端須要得到數據時好比獲取網絡中的圖片,首先從內存中查找(按鍵查找),內存中沒有的再從磁盤文件或 sqlite 中去查找,若磁盤中也沒有才經過網絡獲取

3.LRUCache 原理

LruCache 是個泛型類,主要原理是:把最近使用的對象用強引用存儲在 LinkedHashMap 中,當緩存滿時,把最近最少使用的對象從內存中移除,並提供 get/put 方法完成緩存的獲取和添加,LruCache 是線程安全的,由於使用了 synchronized 關鍵字。

當調用 put()方法,將元素加到鏈表頭,若是鏈表中沒有該元素,大小不變,若是有,需調用 trimToSize 方法判斷是否超過最大緩存量,trimToSize()方法中有一個 while(true)死循環,若是緩存大小大於最大的緩存值,會不斷刪除 LinkedHashMap 中隊尾的元素,即最少訪問的,直到緩存大小小於最大緩存值。

當調用 LruCache 的 get 方法時,LinkedHashMap 會調用recordAccess 方法將此元素加到鏈表頭部

4.Glide 跟Fresco對比

www.jianshu.com/p/1ab5597af…

Glide:

  • 多種圖片格式的緩存,適用於更多的內容表現形式(如Gif、WebP、縮略圖、Video)
  • 生命週期集成(根據Activity或者Fragment的生命週期管理圖片加載請求)
  • 高效處理Bitmap(bitmap的複用和主動回收,減小系統回收壓力)
  • 高效的緩存策略,靈活(Picasso只會緩存原始尺寸的圖片,Glide緩存的是多種規格),加載速度快且內存開銷小(默認Bitmap格式的不一樣,使得內存開銷是Picasso的一半)

Fresco:

  • 最大的優點在於5.0如下(最低2.3)的bitmap加載。在5.0如下系統,Fresco將圖片放到一個特別的內存區域(Ashmem區)
  • 大大減小OOM(在更底層的Native層對OOM進行處理,圖片將再也不佔用App的內存)
  • 適用於須要高性能加載大量圖片的場景
5.假如讓你本身寫個圖片加載框架,你會考慮哪些問題?

首先,梳理一下必要的圖片加載框架的需求:

  • 異步加載:線程池
  • 切換線程:Handler,沒有爭議吧
  • 緩存:LruCache、DiskLruCache
  • 防止OOM:軟引用、LruCache、圖片壓縮、Bitmap像素存儲位置
  • 內存泄露:注意ImageView的正確引用,生命週期管理
  • 列表滑動加載的問題:加載錯亂、隊滿任務過多問題

固然,還有一些不是必要的需求,例如加載動畫等。

1.異步加載

線程池,多少個?

緩存通常有三級,內存緩存、硬盤、網絡。

因爲網絡會阻塞,因此讀內存和硬盤能夠放在一個線程池,網絡須要另一個線程池,網絡也能夠採用Okhttp內置的線程池。

讀硬盤和讀網絡須要放在不一樣的線程池中處理,因此用兩個線程池比較合適。

2.切換線程

圖片異步加載成功,須要在主線程去更新ImageView,

不管是RxJava、EventBus,仍是Glide,只要是想從子線程切換到Android主線程,都離不開Handler。

3.緩存

咱們常說的圖片三級緩存:內存緩存、硬盤緩存、網絡。

**內存緩存:**通常都是用LruCache

Glide 默認內存緩存用的也是LruCache,只不過並無用Android SDK中的LruCache,不過內部一樣是基於LinkHashMap,因此原理是同樣的。

爲何用LruCache?

LruCache 採用最近最少使用算法,設定一個緩存大小,當緩存達到這個大小以後,會將最老的數據移除,避免圖片佔用內存過大致使OOM。

4.防止OOM

加載圖片很是重要的一點是須要防止OOM,上面的LruCache緩存大小設置,能夠有效防止OOM,可是當圖片需求比較大,可能須要設置一個比較大的緩存,這樣的話發生OOM的機率就提升了,那應該探索其它防止OOM的方法。

5.ImageView 內存泄露

Glide的作法是監聽生命週期回調,看 RequestManager 這個類,在Activity/fragment 銷燬的時候,取消圖片加載任務,細節你們能夠本身去看源碼。

6.列表加載問題
相關文章
相關標籤/搜索