您好,登錄后才能下訂單哦!
這幾天在很多地方看到有聊Glide的,想起前年還是去年的時候面試的時候也有問到Glide相關的,正好今天趁著周五來聊一聊面試中Glide的那些東西
請查看完整的PDF版
(更多完整項目下載。未完待續。源碼。圖文知識后續上傳github。)
可以點擊關于我聯系我獲取完整PDF
LruCache
是個泛型類,主要原理是:把最近使用的對象用強引用存儲在 LinkedHashMap
中,當緩存滿時,把最近最少使用的對象從內存中移除,并提供 get/put 方法完成緩存的獲取和添加LruCache
是線程安全的,因為使用了 synchronized 關鍵字。
當調用 put()方法,將元素加到鏈表頭,如果鏈表中沒有該元素,大小不變,如果沒有,需調用 trimToSize
方法判斷是否超過最大緩存量,trimToSize()
方法中有一個 while(true)死循環,如果緩存大小大于最大的緩存值,會不斷刪除 LinkedHashMap
中隊尾的元素,即最少訪問的,直到緩存大小小于最大緩存值。當調用 LruCache
的 get 方法時,LinkedHashMap
會調用recordAccess
方法將此元素加到鏈表頭部
1)Glide.with(context)創建了一個 RequestManager
,同時實現加載圖片與組件生命周期綁定:
在 Activity 上創建一個透明的 ReuqestManagerFragment
加入到 FragmentManager
中,通過添加的 Fragment 感知Activty\Fragment
的生命周期。因為添加到 Activity 中的 Fragment 會跟隨Activity 的生命周期。在 RequestManagerFragment
中的相應生命周期方法中通過 liftcycle
傳遞給在 lifecycle
中注冊的 LifecycleListener
2)RequestManager.load(url)
創建了一個 RequestBuilder<T>
對象 T 可以是 Drawable
對象或是 ResourceType
等
3 ) RequestBuilder.into(view)
-->into(glideContext.buildImageViewTarget(view, transcodeClass))
返 回 的 是 一 個DrawableImageViewTarget
, Target 用 來 最 終 展 示 圖 片 的 ,buildImageViewTarget
-->ImageViewTargetFactory.buildTarget()
根據傳入 class 參數不同構建不同的 Target 對象,這個 Class 是根據構建 Glide 時是否調用了 asBitmap()
方法,如果調用了會構建出BitmapImageViewTarget
,否則構建的是GlideDrawableImageViewTarget
對象。
-->GenericRequestBuilder.into(Target)
, 該 方 法 進 行 了 構 建 Request , 并 用RequestTracker.runRequest()
-->GenericRequest.begin()
Request request = buildRequest(target);
// 構建 Request 對象,
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
// 判斷 Glide 當前是不是處于暫停狀態
onSizeReady()
--> `Engine.load(signature, width, height, dataFetcher, loadProvider,transformation, transcoder,priority, isMemoryCacheable, diskCacheStrategy, this)
a)先構建
EngineKey;
b)`loadFromCache
從 緩 存 中 獲 取 EngineResource
, 如 果 緩 存 中 獲 取 到 cache 就 調 用`cb.onResourceReady(cached);
c)如果緩存中不存在調用
loadFromActiveResources從 active中獲取,如果獲取到就調用
cb.onResourceReady(cached);
d)如果 active 中也不存在,調用
EngineJob.start(EngineRunnable), 從而調用
decodeFromSource()/decodeFromCache()-->如果是調 用
decodeFromSource()-->
ImageVideoFetcher.loadData()-->
HttpUrlFetcher()調 用
HttpUrlConnection進 行 網 絡 請 求 資 源 --> 得 于
InputStream()后 , 調 用
decodeFromSourceData()-->
loadProvider.getSourceDecoder().decode() 方 法 解 碼-->
GifBitmapWrapperResourceDecoder.decode()-->
decodeStream()先從流中讀取 2 個字節判斷是 GIF 還是普通圖,若是 GIF 調用
decodeGifWrapper()來解碼,若是普通靜圖則調用
decodeBitmapWrapper()來解碼-->
bitmapDecoder.decode()`
1) 內存緩存: LruResourceCache(memory)+
弱引用 activeResources
Map
<Key, WeakReference
<EngineResource
<?>>> activeResources
正在使用的資源,當 acquired變量大于 0,說明圖片正在使用,放到 activeResources
弱引用緩存中,經過 release()
后,acquired=0,說明圖片不再使用,會把它放進 LruResourceCache
中
2)磁盤緩存: DiskLruCache
,這里分為 Source(原始圖片)和 Result(轉換后的圖片)
第一次獲取圖片,肯定網絡取,然后存 active\disk 中,再把圖片顯示出來,第二次讀取相同的圖片,并加載到相同大小的 imageview
中,會先從 memory 中取,沒有再去 active 中獲取。如果 activity 執行到 onStop
時,圖片被回收,active 中的資源會被保存到memory 中,active中的資源被回收。當再次加載圖片時,會從 memory 中取,再放入 active 中,并將 memory中對應的資源回收。
之所以需要 activeResources
,它是一個隨時可能被回收的資源,memory 的強引用頻繁讀寫可能造成內存激增頻繁 GC
,而造成內存抖動。資源在使用過程中保存在 activeResources
中,而 activeResources
是弱引用,隨時被系統回收,不會造成內存過多使用和泄漏。
Glide 內存緩存最大空間(maxSize)=每個進程可用最大內存0.4(低配手機是 每個進程可用最大內存0.33)
磁盤緩存大小是 250MB int DEFAULT_DISK_CACHE_SIZE = 250 1024 1024;
LruCache
中 Lru
算法的實現就是通過 LinkedHashMap
來實現的。LinkedHashMap
繼承于HashMap
,它使用了一個雙向鏈表來存儲 Map 中的 Entry 順序關系,對于 get、put、remove 等操作,LinkedHashMap
除了要做 HashMap
做的事情,還做些調整 Entry 順序鏈表的工作。
LruCache
中將 LinkedHashMap
的順序設置為 LRU
順序來實現 LRU 緩存,每次調用 get(也就是從內存緩存中取圖片),則將該對象移到鏈表的尾端。調用 put 插入新的對象也是存儲在鏈表尾端,這樣當內存緩存達到設定的最大值時,將鏈表頭部的對象(近期最少用到的)移除。
當 Android 端需要獲得數據時比如獲取網絡中的圖片,首先從內存中查找(按鍵查找),內存中沒有的再從磁盤文件或 sqlite
中去查找,若磁盤中也沒有才通過網絡獲取
圖片加載包含封裝,解析,下載,解碼,變換,緩存,顯示等操作
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。