聊一聊關於Glide在面試中的那些事

1.前言

今天填完離職表,幫着公司面試幾個幫着填坑的同行,聊着聊着就聊到了Glide,信誓旦旦的和我說,這塊很熟悉,以前在掘金社區裏,看過一個叫藍師傅寫的這塊的文章,基本細節都掌握😏。(一副勝利在望的表情,好吧,正巧我也看過,我們就問一問看的仔細狀況)java


2. 來簡單介紹下Glide的緩存

2.1 分析

(這貨口若懸河的說了一大通,從LruCache說到了LinkedHashMap,巴拉巴拉。。。我的建議這塊必定要簡述,面試時原理說的太多,第一不少細節會被打斷問到,第二點,說這麼多,給人的感受就是在背誦東西,原理歸納能力很弱或者感受根本就沒有本身的體會。)面試

2.2 答案

Glide的緩存機制,主要分爲2種緩存,一種是內存緩存,一種是磁盤緩存。 之因此使用內存緩存的緣由是:防止應用重複將圖片讀入到內存,形成內存資源浪費。 之因此使用磁盤緩存的緣由是:防止應用重複的從網絡或者其餘地方下載和讀取數據。 正式由於有着這兩種緩存的結合,才構成了Glide極佳的緩存效果。算法

(先告訴人家有哪幾種緩存,主要是爲了什麼目的才用的緩存,而後能夠看着面試官,要麼等着他繼續問,若是他不問,等着你,這個時候你就能夠繼續的往細節處介紹)緩存


3. 嗯,具體說一說Glide的三級緩存原理

3.1 分析

(記得,若是須要具體談原理時,要先宏觀,後細節)網絡

3.2 答案

讀取一張圖片的時候,獲取順序: Lru算法緩存-》弱引用緩存-》磁盤緩存(若是設置了的話)app

當咱們的APP中想要加載某張圖片時,先去LruCache中尋找圖片,若是LruCache中有,則直接取出來使用,並將該圖片放入WeakReference中,若是LruCache中沒有,則去WeakReference中尋找,若是WeakReference中有,則從WeakReference中取出圖片使用,若是WeakReference中也沒有圖片,則從磁盤緩存/網絡中加載圖片。框架

注:圖片正在使用時存在於 activeResources 弱引用map中ide

流程以下圖 學習

將圖片緩存的時候,寫入順序: 弱引用緩存-》Lru算法緩存-》磁盤緩存中動畫

當圖片不存在的時候,先從網絡下載圖片,而後將圖片存入弱引用中,glide會採用一個acquired(int)變量用來記錄圖片被引用的次數, 當acquired變量大於0的時候,說明圖片正在使用中,也就是將圖片放到弱引用緩存當中; 若是acquired變量等於0了,說明圖片已經再也不被使用了,那麼此時會調用方法來釋放資源,首先會將緩存圖片從弱引用中移除,而後再將它put到LruResourceCache當中。 這樣也就實現了正在使用中的圖片使用弱引用來進行緩存,不在使用中的圖片使用LruCache來進行緩存的功能。

引深: 關於LruCache

最近最少使用算法,設定一個緩存大小,當緩存達到這個大小以後,會將最老的數據移除,避免圖片佔用內存過大致使OOM。 LruCache 內部用LinkHashMap存取數據,在雙向鏈表保證數據新舊順序的前提下,設置一個最大內存,往裏面put數據的時候,當數據達到最大內存的時候,將最老的數據移除掉,保證內存不超過設定的最大值。

關於LinkedHashMap

LinkHashMap 繼承HashMap,在 HashMap的基礎上,新增了雙向鏈表結構,每次訪問數據的時候,會更新被訪問的數據的鏈表指針,具體就是先在鏈表中刪除該節點,而後添加到鏈表頭header以前,這樣就保證了鏈表頭header節點以前的數據都是最近訪問的(從鏈表中刪除並非真的刪除數據,只是移動鏈表指針,數據自己在map中的位置是不變的)


4. Glide加載一個一兆的圖片(100 * 100),是否會壓縮後再加載,放到一個300 * 300的view上會怎樣,800*800呢,圖片會很模糊,怎麼處理?

4.1 分析

(由於你緩存機制不管是看博客仍是看一些面試寶典,若是隻是考原理或者定義,光把上面的文字背誦下來就能夠了,可是背誦和真正的理解是兩回事,本身沒有造成感悟,不理解這個框架,只是一味的迎合面試,這個問題就能夠卡住你,另外千萬別和麪試官嘚瑟,果真,這個面試的哥們,這塊就卡住了,支支吾吾的半天沒答上來,果真是隻看了博客,沒真正的閱讀過源碼)

4.2 答案

當咱們調整imageview的大小時,Picasso會無論imageview大小是什麼,老是直接緩存整張圖片,而Glide就不同了,它會爲每一個不一樣尺寸的Imageview緩存一張圖片,也就是說無論你的這張圖片有沒有加載過,只要imageview的尺寸不同,那麼Glide就會從新加載一次,這時候,它會在加載的imageview以前從網絡上從新下載,而後再緩存。

舉個例子,若是一個頁面的imageview是300 * 300像素,而另外一個頁面中的imageview是100 * 100像素,這時候想要讓兩個imageview像是同一張圖片,那麼Glide須要下載兩次圖片,而且緩存兩張圖片。

public <R> LoadStatus load() {
    // 根據請求參數獲得緩存的鍵
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
}
複製代碼

看到了吧,緩存Key的生成條件之一就是控件的長寬。


5. 簡單說一下內存泄漏的場景,若是在一個頁面中使用Glide加載了一張圖片,圖片正在獲取中,若是忽然關閉頁面,這個頁面會形成內存泄漏嗎?

5.1 分析

(注意必定要審題,由於以前問了這個小夥,內存泄漏的緣由,無非是長生命週期引用了短生命週期的對象等等,而後忽然畫風一變,直接問了Glide加載圖片會不會引發圖片泄漏,這個小夥想也沒想,直接回答道會引發內存泄漏,能夠用LeakCanary檢測,巴拉巴拉。。。)

5.2 答案

由於Glide 在加載資源的時候,若是是在 Activity、Fragment 這一類有生命週期的組件上進行的話,會建立一個透明的 RequestManagerFragment 加入到FragmentManager 之中,感知生命週期,當 Activity、Fragment 等組件進入不可見,或者已經銷燬的時候,Glide 會中止加載資源。

可是若是,是在非生命週期的組件上進行時,會採用Application 的生命週期貫穿整個應用,因此 applicationManager 只有在應用程序關閉的時候終止加載。


6.如何設計一個大圖加載框架

6.1 分析

(這個孩子,總算是羞愧的低下了頭,一臉懵逼的和我說,這個我忘記了)

6.2 答案

歸納來講,圖片加載包含封裝,解析,下載,解碼,變換,緩存,顯示等操做。

  1. 封裝參數:從指定來源,到輸出結果,中間可能經歷不少流程,因此第一件事就是封裝參數,這些參數會貫穿整個過程;
  2. 解析路徑:圖片的來源有多種,格式也不盡相同,須要規範化;
  3. 讀取緩存:爲了減小計算,一般都會作緩存;一樣的請求,從緩存中取圖片(Bitmap)便可;
  4. 查找文件/下載文件:若是是本地的文件,直接解碼便可;若是是網絡圖片,須要先下載;
  5. 解碼:這一步是整個過程當中最複雜的步驟之一,有很多細節,下個博客會說;
  6. 變換:解碼出Bitmap以後,可能還須要作一些變換處理(圓角,濾鏡等);
  7. 緩存:獲得最終bitmap以後,能夠緩存起來,以便下次請求時直接取結果;
  8. 顯示:顯示結果,可能須要作些動畫(淡入動畫,crossFade等)。

END

先寫到這,基本上問的也就這麼多了,要是再細扣,感受有些故意爲難了,面試的通常都是在30分鐘之內,感受對方會的,我會跳過,由於你會了,我就不必問了,浪費時間,感受不會的,問道你說出不會或者不清楚爲止,我也不會再在這方面細扣,緣由也是同樣,浪費時間。主要是發現每一個人的長處,及對待事情的態度。

另外其實吧,不必定都答的上來纔會要你,也不是由於答不上來就不要你,主要吧,仍是靠感受,好相處,人又不是太滑,性格nice,給人踏實的感受的,都會網開一面的。

下期我會仿照着Glide本身仿照一個,將Glide的主流程所涉及的,都會加上,這樣方便你們的理解。有興趣的能夠關注我。

仍是那句話 雖然更新時間沒準,快則半天,慢則半年,可是每一篇文章,我都深刻淺出,要麼豐富的流程圖,一看就懂,要麼就是一步一步仿照着寫,學習框架原理仍是那句話,先搞清楚爲何要這麼設計,可不能夠不這麼寫或者不加這個功能,根據情境分析,而後再去解讀這塊源碼邏輯,這樣纔會記的牢固

相關文章
相關標籤/搜索