溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

原來面試的時候?qū)懢℅lide,這樣問我這樣答

發(fā)布時間:2020-06-11 19:30:06 來源:網(wǎng)絡(luò) 閱讀:582 作者:Android丶VG 欄目:移動開發(fā)
前言

這幾天在很多地方看到有聊Glide的,想起前年還是去年的時候面試的時候也有問到Glide相關(guān)的,正好今天趁著周五來聊一聊面試中Glide的那些東西

  • 1 、圖片庫對比
  • 2 、LRUCache 原理
  • 3丶LruCache 底層實現(xiàn)原理
  • 4 、圖片加載原理
  • 5 、自己去實現(xiàn)圖片庫,怎么做?
  • 6 、Glide 源碼解析
  • 7 、Glide 使用什么緩存
  • 8 、Glide 內(nèi)存緩存如何控制大???
  • 9丶三級緩存原理?
  • 10丶如何設(shè)計一個大圖加載框架?
    面試整理學(xué)習(xí)路線(禁止偷偷拿走O(∩_∩)O)

    原來面試的時候?qū)懢℅lide,這樣問我這樣答
    請查看完整的PDF版
    (更多完整項目下載。未完待續(xù)。源碼。圖文知識后續(xù)上傳github。)
    可以點擊關(guān)于我聯(lián)系我獲取完整PDF

一丶LRUCache 原理

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

當(dāng)調(diào)用 put()方法,將元素加到鏈表頭,如果鏈表中沒有該元素,大小不變,如果沒有,需調(diào)用 trimToSize 方法判斷是否超過最大緩存量,trimToSize()方法中有一個 while(true)死循環(huán),如果緩存大小大于最大的緩存值,會不斷刪除 LinkedHashMap 中隊尾的元素,即最少訪問的,直到緩存大小小于最大緩存值。當(dāng)調(diào)用 LruCache 的 get 方法時,LinkedHashMap 會調(diào)用recordAccess 方法將此元素加到鏈表頭部

二、Glide 源碼解析

1)Glide.with(context)創(chuàng)建了一個 RequestManager,同時實現(xiàn)加載圖片與組件生命周期綁定:
在 Activity 上創(chuàng)建一個透明的 ReuqestManagerFragment 加入到 FragmentManager 中,通過添加的 Fragment 感知Activty\Fragment 的生命周期。因為添加到 Activity 中的 Fragment 會跟隨Activity 的生命周期。在 RequestManagerFragment 中的相應(yīng)生命周期方法中通過 liftcycle 傳遞給在 lifecycle 中注冊的 LifecycleListener

2)RequestManager.load(url) 創(chuàng)建了一個 RequestBuilder<T>對象 T 可以是 Drawable 對象或是 ResourceType

3 ) RequestBuilder.into(view)-->into(glideContext.buildImageViewTarget(view, transcodeClass))返 回 的 是 一 個DrawableImageViewTarget, Target 用 來 最 終 展 示 圖 片 的 ,buildImageViewTarget-->ImageViewTargetFactory.buildTarget()根據(jù)傳入 class 參數(shù)不同構(gòu)建不同的 Target 對象,這個 Class 是根據(jù)構(gòu)建 Glide 時是否調(diào)用了 asBitmap()方法,如果調(diào)用了會構(gòu)建出BitmapImageViewTarget,否則構(gòu)建的是GlideDrawableImageViewTarget 對象。
-->GenericRequestBuilder.into(Target), 該 方 法 進 行 了 構(gòu) 建 Request , 并 用RequestTracker.runRequest()-->GenericRequest.begin()

 Request request = buildRequest(target);
         // 構(gòu)建 Request 對象, 
        target.setRequest(request);
        lifecycle.addListener(target);
 requestTracker.runRequest(request);
       // 判斷 Glide 當(dāng)前是不是處于暫停狀態(tài)

onSizeReady()--> `Engine.load(signature, width, height, dataFetcher, loadProvider,transformation, transcoder,priority, isMemoryCacheable, diskCacheStrategy, this)

a)先構(gòu)建EngineKey;

b)`loadFromCache 從 緩 存 中 獲 取 EngineResource , 如 果 緩 存 中 獲 取 到 cache 就 調(diào) 用`cb.onResourceReady(cached);

c)如果緩存中不存在調(diào)用loadFromActiveResources從 active中獲取,如果獲取到就調(diào)用cb.onResourceReady(cached);

d)如果 active 中也不存在,調(diào)用EngineJob.start(EngineRunnable), 從而調(diào)用decodeFromSource()/decodeFromCache()-->如果是調(diào) 用decodeFromSource()-->ImageVideoFetcher.loadData()-->HttpUrlFetcher()調(diào) 用HttpUrlConnection進 行 網(wǎng) 絡(luò) 請 求 資 源 --> 得 于InputStream()后 , 調(diào) 用decodeFromSourceData()-->loadProvider.getSourceDecoder().decode() 方 法 解 碼-->GifBitmapWrapperResourceDecoder.decode()-->decodeStream()先從流中讀取 2 個字節(jié)判斷是 GIF 還是普通圖,若是 GIF 調(diào)用decodeGifWrapper()來解碼,若是普通靜圖則調(diào)用decodeBitmapWrapper()來解碼-->bitmapDecoder.decode()`

三丶Glide 使用什么緩存?

1) 內(nèi)存緩存: LruResourceCache(memory)+弱引用 activeResources
Map<Key, WeakReference<EngineResource<?>>> activeResources正在使用的資源,當(dāng) acquired變量大于 0,說明圖片正在使用,放到 activeResources 弱引用緩存中,經(jīng)過 release()后,acquired=0,說明圖片不再使用,會把它放進 LruResourceCache

2)磁盤緩存: DiskLruCache,這里分為 Source(原始圖片)和 Result(轉(zhuǎn)換后的圖片)

第一次獲取圖片,肯定網(wǎng)絡(luò)取,然后存 active\disk 中,再把圖片顯示出來,第二次讀取相同的圖片,并加載到相同大小的 imageview 中,會先從 memory 中取,沒有再去 active 中獲取。如果 activity 執(zhí)行到 onStop 時,圖片被回收,active 中的資源會被保存到memory 中,active中的資源被回收。當(dāng)再次加載圖片時,會從 memory 中取,再放入 active 中,并將 memory中對應(yīng)的資源回收。

之所以需要 activeResources,它是一個隨時可能被回收的資源,memory 的強引用頻繁讀寫可能造成內(nèi)存激增頻繁 GC,而造成內(nèi)存抖動。資源在使用過程中保存在 activeResources 中,而 activeResources 是弱引用,隨時被系統(tǒng)回收,不會造成內(nèi)存過多使用和泄漏。

四丶Glide 內(nèi)存緩存如何控制大小?

Glide 內(nèi)存緩存最大空間(maxSize)=每個進程可用最大內(nèi)存0.4(低配手機是 每個進程可用最大內(nèi)存0.33)

磁盤緩存大小是 250MB int DEFAULT_DISK_CACHE_SIZE = 250 1024 1024;

五丶LruCache 底層實現(xiàn)原理:

LruCacheLru 算法的實現(xiàn)就是通過 LinkedHashMap 來實現(xiàn)的。LinkedHashMap繼承于HashMap,它使用了一個雙向鏈表來存儲 Map 中的 Entry 順序關(guān)系,對于 get、put、remove 等操作,LinkedHashMap 除了要做 HashMap 做的事情,還做些調(diào)整 Entry 順序鏈表的工作。

LruCache 中將 LinkedHashMap 的順序設(shè)置為 LRU 順序來實現(xiàn) LRU 緩存,每次調(diào)用 get(也就是從內(nèi)存緩存中取圖片),則將該對象移到鏈表的尾端。調(diào)用 put 插入新的對象也是存儲在鏈表尾端,這樣當(dāng)內(nèi)存緩存達到設(shè)定的最大值時,將鏈表頭部的對象(近期最少用到的)移除。

六丶三級緩存原理

當(dāng) Android 端需要獲得數(shù)據(jù)時比如獲取網(wǎng)絡(luò)中的圖片,首先從內(nèi)存中查找(按鍵查找),內(nèi)存中沒有的再從磁盤文件或 sqlite 中去查找,若磁盤中也沒有才通過網(wǎng)絡(luò)獲取

七丶如何設(shè)計一個大圖加載框架

圖片加載包含封裝,解析,下載,解碼,變換,緩存,顯示等操作

  • 封裝參數(shù): 從指定來源,到輸出結(jié)果,中間可能經(jīng)歷很多流程,所以第一件事就是封裝參數(shù),這些參數(shù)會貫穿整個過程;
  • 解析路徑: 圖片的來源有多種,格式也不盡相同,需要規(guī)范化;
  • 讀取緩存: 為了減少計算,通常都會做緩存;同樣的請求,從緩存中取圖片(Bitmap)即可;
  • 查找文件/下載文件: 如果是本地的文件,直接解碼即可;如果是網(wǎng)絡(luò)圖片,需要先下載;
  • 解碼: 這一步是整個過程中最復(fù)雜的步驟之一,有不少細節(jié),下個博客會說;
  • 變換: 解碼出Bitmap之后,可能還需要做一些變換處理(圓角,濾鏡等);
  • 緩存: 得到最終bitmap之后,可以緩存起來,以便下次請求時直接取結(jié)果;
  • 顯示: 顯示結(jié)果,可能需要做些動畫(淡入動畫,crossFade等)
    原來面試的時候?qū)懢℅lide,這樣問我這樣答
    請查看完整的PDF版
    (更多完整項目下載。未完待續(xù)。源碼。圖文知識后續(xù)上傳github。)
    可以點擊關(guān)于我聯(lián)系我獲取完整PDF
向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI