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給了咱們這麼完美的解決方案咱們就要學以至用,之後盡力用到本身的工程中去。網絡
咱們能夠知道.with()
方法返回的是GlideRequests
對象,GlideRequests
是繼承自RequestManager
(負責管理和請求Glide的請求類),框架
返回 RequestBuilder 對象
- 獲得ImageViewTarget 顯示圖片的地方
return into(
// 獲得ImageViewTarget 顯示圖片的地方
glideContext.buildImageViewTarget(view, transcodeClass));
複製代碼
- 構建一個請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
複製代碼
當咱們調整ImageView大小事,Glide會爲每一個不一樣尺寸的ImageView緩存一張圖片,也就是說無論你的這張圖片有沒有被加載過,只要ImageView的尺寸不同,那麼GLide就會從新加載一次,這時候,他會在加載ImageView以前從網絡上從新下載,而後再緩存。 舉個例子,若是一個頁面的ImageView是300 * 300像素,而另外一個頁面中的ImageView是100 * 100像素,這時候想要讓兩個ImageView是同一張圖片,那麼Glide須要下載兩次圖片,而且緩存兩張圖片。
當 Android 端須要得到數據時好比獲取網絡中的圖片,首先從內存中查找(按鍵查找),內存中沒有的再從磁盤文件或
sqlite
中去查找,若磁盤中也沒有才經過網絡獲取
LruCache
是個泛型類,主要原理是:把最近使用的對象用強引用存儲在LinkedHashMap
中,當緩存滿時,把最近最少使用的對象從內存中移除,並提供 get/put 方法完成緩存的獲取和添加,LruCache
是線程安全的,由於使用了 synchronized 關鍵字。
當調用 put()方法,將元素加到鏈表頭,若是鏈表中沒有該元素,大小不變,若是有,需調用
trimToSize
方法判斷是否超過最大緩存量,trimToSize()
方法中有一個 while(true)死循環,若是緩存大小大於最大的緩存值,會不斷刪除LinkedHashMap
中隊尾的元素,即最少訪問的,直到緩存大小小於最大緩存值。當調用
LruCache
的 get 方法時,LinkedHashMap
會調用recordAccess
方法將此元素加到鏈表頭部
Glide:
Fresco:
首先,梳理一下必要的圖片加載框架的需求:
固然,還有一些不是必要的需求,例如加載動畫等。
線程池,多少個?
緩存通常有三級,內存緩存、硬盤、網絡。
因爲網絡會阻塞,因此讀內存和硬盤能夠放在一個線程池,網絡須要另一個線程池,網絡也能夠採用Okhttp內置的線程池。
讀硬盤和讀網絡須要放在不一樣的線程池中處理,因此用兩個線程池比較合適。
圖片異步加載成功,須要在主線程去更新ImageView,
不管是RxJava、EventBus,仍是Glide,只要是想從子線程切換到Android主線程,都離不開Handler。
咱們常說的圖片三級緩存:內存緩存、硬盤緩存、網絡。
**內存緩存:**通常都是用
LruCache
Glide 默認內存緩存用的也是LruCache,只不過並無用Android SDK中的LruCache,不過內部一樣是基於LinkHashMap,因此原理是同樣的。
爲何用LruCache?
LruCache 採用最近最少使用算法,設定一個緩存大小,當緩存達到這個大小以後,會將最老的數據移除,避免圖片佔用內存過大致使OOM。
加載圖片很是重要的一點是須要防止OOM,上面的LruCache緩存大小設置,能夠有效防止OOM,可是當圖片需求比較大,可能須要設置一個比較大的緩存,這樣的話發生OOM的機率就提升了,那應該探索其它防止OOM的方法。
Glide的作法是監聽生命週期回調,看 RequestManager
這個類,在Activity/fragment 銷燬的時候,取消圖片加載任務,細節你們能夠本身去看源碼。