久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

探索 Glide 原理

 codingSmart 2021-10-22

code小生 一個(gè)專注大前端領(lǐng)域的技術(shù)平臺(tái)公眾號(hào)回復(fù)Android加入安卓技術(shù)群

作者: 燈不利多
鏈接:https:///post/6882536990400020494
聲明:本文已獲 燈不利多授權(quán)發(fā)表,,轉(zhuǎn)發(fā)等請(qǐng)聯(lián)系原作者授權(quán)

前言

1. Glide 基本用法

接下來的講解將基于 Glide 目前的最新版本 4.11,。

Glide 的使用特別簡單,首先添加依賴,。

然后調(diào)用下面這三個(gè)方法,。

  • with()

    可以傳 Applicaiton、Activity ,、Fragment 與 view 等類型的參數(shù),,加載圖片的請(qǐng)求會(huì)與該參數(shù)的生命周期綁定在一起。

  • load()

    可以傳圖片的網(wǎng)絡(luò)地址,、Drawable 等,。

  • into()

    一般傳 ImageView 。

2. 內(nèi)容概覽

Glide 加載圖片大致可分為三個(gè)步驟,。

  1. 發(fā)起加載圖片請(qǐng)求

    當(dāng)我們用 into() 方法加載圖片時(shí),就是發(fā)起了一次圖片加載請(qǐng)求;

  2. 執(zhí)行解碼任務(wù)

    我們?cè)?load() 方法中設(shè)置的圖片來源會(huì)傳到 DecodeJob 中,,DecodeJob 就會(huì)被 Engine 提交到線程池中開始執(zhí)行,;

  3. 加載圖片

    當(dāng) DecodeJob 對(duì)圖片解碼完成后,就會(huì)把圖片加載到 ImageView 中,;

接下來會(huì)以這三個(gè)步驟為基礎(chǔ)來展開 Glide 的圖片加載流程,,下面是每個(gè)大節(jié)講解的內(nèi)容。

1. 四步啟動(dòng)解碼任務(wù)

第一大節(jié)將會(huì)講解從我們調(diào)用 into() 方法到啟動(dòng) DecodeJob 的 run() 方法的過程中,,Glide 做了哪些事情,,包含了 Request、Target ,、 Engine 和 DecodeJob 等內(nèi)容,。

2. 六步加載圖片

第二大節(jié)會(huì)講解當(dāng) DecodeJob 獲取到圖片數(shù)據(jù)后,會(huì)怎么處理圖片數(shù)據(jù),,也就是解碼,、加載圖片和編碼的過程,包括 ModelLoader,、ResourceDecoder,、Transformation、ResourceTranscoder 以及 ResourceEncoder 的實(shí)現(xiàn),。

3. Glide 緩存原理

這里會(huì)講 Glide 的圖片緩存相關(guān)的實(shí)現(xiàn),,包括內(nèi)存緩存、磁盤緩存,、BitmapPool 以及 ArrayPool 等內(nèi)容,。

4. Glide 初始化流程與配置

這一節(jié)會(huì)講解 Glide 的初始化流程,包括 Glide 調(diào)用配置的方式,、AppGlideModule 的兩個(gè)方法中用到的 Registry 和 GlideBuilder 在 Glide 中的作用,。

5. Glide 圖片加載選項(xiàng)

Glide 開放了非常多的圖片加載選項(xiàng),我們不一定全都用得上,,但是了解這些選項(xiàng),,可以讓我們?cè)谛枰臅r(shí)候能調(diào)用對(duì)應(yīng)的選項(xiàng),不用再自己實(shí)現(xiàn)一遍,。

1. 四步啟動(dòng)解碼任務(wù)

這一節(jié)我們先來看下從 into() 到啟動(dòng) DecodeJob 的過程中涉及哪些對(duì)象,。

從我們調(diào)用 into() 方法加載圖片到啟動(dòng)解碼任務(wù) DecodeJob,大致分為 4 個(gè)步驟,,涉及下面 4 個(gè)對(duì)象,。

  1. 加載請(qǐng)求 Request
  2. 加載目標(biāo) Target
  3. 加載引擎 Engine
  4. 解碼任務(wù) DecodeJob

下面我們圍繞這 4 個(gè)對(duì)象看看 Glide 的解碼任務(wù)的啟動(dòng)流程。

1.1 Request

1.1.1 請(qǐng)求構(gòu)建器 RequestBuilder

1. into()

對(duì)于我們發(fā)起的圖片加載請(qǐng)求,,Glide 會(huì)把這個(gè)請(qǐng)求封裝為 Request,,而 RequestBuilder 就是 Request 的構(gòu)建器,。

當(dāng)我們用 into() 方法加載圖片時(shí),調(diào)用的其實(shí)是 RequestBuilder 的 into() 方法,,這個(gè)方法會(huì)創(chuàng)建一個(gè) Request ,,并把 Request 傳給請(qǐng)求管理器。

2. Model

Glide 會(huì)把我們?cè)?load() 中傳入的圖片來源數(shù)據(jù)封裝為 Model ,,而這個(gè) Model 具體就是 RequestBuilder 中的 model 字段,,類型為 Object 。

3. 加載選項(xiàng)

RequestBuilder 繼承了 BaseRequestOptions 抽象類,,我們平時(shí)用的 centerCrop() 等方法大部分都是 BaseRequestOptions 的方法,,關(guān)于圖片加載選項(xiàng)在后面會(huì)講到。

1.1.2 請(qǐng)求管理器 RequestManager

RequestManager 有下面幾個(gè)特點(diǎn),。

  • 綁定生命周期
  • 監(jiān)聽網(wǎng)絡(luò)狀態(tài)
  • 創(chuàng)建請(qǐng)求構(gòu)建器
  • 啟動(dòng)請(qǐng)求
1. 綁定生命周期

在 Glide 中,,一個(gè) Context 對(duì)應(yīng)一個(gè) RequestManager,當(dāng)我們調(diào)用 with() 方法時(shí),,RequestManager 會(huì)用對(duì)應(yīng)的 Context 創(chuàng)建一個(gè) RequestManagerFragment ,。

RequestManagerFragment 是一個(gè)無布局的 Fragment,主要是用來做生命周期關(guān)聯(lián)的,,當(dāng)這個(gè) Fragment 感知到 Activity 的生命周期發(fā)生變化時(shí),,就會(huì)告訴請(qǐng)求管理器,讓它去做暫停請(qǐng)求,、繼續(xù)請(qǐng)求和取消請(qǐng)求等操作,。

如果我們用的是 ApplicationContext 加載某張圖片,那就意味著這次圖片加載操作的生命周期是與應(yīng)用的生命周期綁定的,。

2. 監(jiān)聽網(wǎng)絡(luò)狀態(tài)

RequestManager 中有一個(gè)網(wǎng)絡(luò)連接監(jiān)聽器 RequestManagerConnectivityListener ,,它實(shí)現(xiàn)了ConnectivityListener 接口,每次網(wǎng)絡(luò)狀態(tài)切換時(shí),,RequestManager 就會(huì)重啟所有的圖片加載請(qǐng)求,。

3. 創(chuàng)建請(qǐng)求構(gòu)建器

我們?cè)诩虞d圖片時(shí)調(diào)用的 load() 方法是 RequestManager 的方法,調(diào)用這個(gè)方法其實(shí)是創(chuàng)建了一個(gè)請(qǐng)求構(gòu)建器 RequestBuilder,,RequestManager 中有很多創(chuàng)建 RequestBuilder 的方法,,比如 asDrawable()、asBitmap() ,、asFile() 等,,這些方法對(duì)應(yīng)著不同泛型參數(shù)的 RequestBuilder 。

load() 方法支持下面這些類型的參數(shù),。

  • Bitmap
  • Drawable
  • String
  • Uri
  • URL
  • File
  • Integer(resourceId)
  • byte[]
  • Object
4. 啟動(dòng)請(qǐng)求

RequestManager 的 track() 方法調(diào)用了目標(biāo)跟蹤器 TargetTracker 的 track() 方法,,還調(diào)用了請(qǐng)求跟蹤器 RequestTracker 的 runRequest() 方法 。

  • TargetTracker

    TargetTracker 實(shí)現(xiàn)了 LifecycleListener ,,它會(huì)根據(jù)頁面生命周期播放和暫停動(dòng)畫,,比如暫停 Gif 動(dòng)畫,。

  • RequestTracker

    RequestTracker 的 runRequest() 方法調(diào)用了 Request.begin() 方法。

    在 Request 的 begin() 方法中會(huì)獲取 View 的尺寸,,獲取到了尺寸后就會(huì)調(diào)用 Engine 的 load() 方法啟動(dòng)圖片加載請(qǐng)求,。

1.1.3 Request 的 6 種狀態(tài)

前面講到的 Request 具體就是 SingleRequest ,SingleRequest 中有一個(gè) Status 枚舉類,,包含了請(qǐng)求的 6 種狀態(tài)。

1. 待運(yùn)行 PENDING

當(dāng)我們通過 into() 創(chuàng)建了一個(gè) SingleRequest 后,,該 Request 就進(jìn)入了待運(yùn)行狀態(tài),。

2. 已清除 CLEARED

每次我們用 into() 方法加載圖片時(shí),RequestManager 都會(huì)先看下我們傳入的 Target 是否有對(duì)應(yīng)的 Request ,,如果有的話就會(huì)調(diào)用該 Request 的 clear() 方法釋放資源,,這時(shí) Request 就進(jìn)入了已清除狀態(tài)。

3. 待測(cè)量 WAITING_FOR_SIZE

當(dāng) RequestManager 調(diào)用 RequestTracker 的 runRequest() 方法后,,RequestTracker 就會(huì)調(diào)用 Request 的 begin() 方法,,這時(shí)請(qǐng)求就進(jìn)入了待測(cè)量狀態(tài),。

4. 運(yùn)行中 RUNNING

在 SingleRequest 的 begin() 方法中,,調(diào)用了 Target 的 getSize() 方法獲取 ImageView 的尺寸,獲取到尺寸后,,SingleRequst 會(huì)調(diào)用 Engine 的 load() 方法啟動(dòng)圖片加載請(qǐng)求,,這時(shí) Request 就進(jìn)入了運(yùn)行中狀態(tài)。

5. 已完成 COMPLETE

當(dāng) Engine 從內(nèi)存中加載到資源,,或者通過解碼任務(wù)加載到資源后,,就會(huì)調(diào)用 SingleRequest 的 onResourceReady() 方法,,這時(shí) Request 就進(jìn)入了已完成狀態(tài),。

6. 失敗 FAILED

當(dāng)解碼任務(wù) DecodeJob 在處理圖片的過程中遇到異常時(shí),,就會(huì)調(diào)用 EngineJob 的 onLoadFailed() 方法,然后 EngineJob 會(huì)調(diào)用 SingleRequest 的 onLoadFailed() 方法,,這時(shí) SingleRequest 就進(jìn)入了失敗狀態(tài),。

1.1.4 三種占位圖

我們?cè)诩虞d圖片時(shí),可以設(shè)置 placeholder,、error 和 fallback 三種占位圖,。

  • placeholder

    圖片加載完成前顯示的占位圖;

  • error

    圖片加載失敗時(shí)顯示的占位圖,;

  • fallback

    圖片來源為空時(shí)顯示的占位圖,;

使用占位圖時(shí),要注意占位圖是不會(huì)使用 Transformation 進(jìn)行變換的,,如果你想弄個(gè)圓角或圓形的占位圖,,可以用 submit().get() 獲取對(duì)應(yīng)變換后的占位圖的 Drawable 對(duì)象,然后傳到對(duì)應(yīng)的占位圖設(shè)置方法中,。

1.1.5 Request 相關(guān)問題

下面是幾個(gè)跟 Request 相關(guān)的問題,,看看你能不能答得上來。

  1. 我們平時(shí)用 Glide 加載圖片調(diào)用的 into() 方法是哪個(gè)類的方法,?
  2. 當(dāng)設(shè)備的網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí),,是誰負(fù)責(zé)重啟圖片加載請(qǐng)求?
  3. Request 有哪幾種狀態(tài),?這些狀態(tài)是如何流轉(zhuǎn)的,?
  4. Glide 有幾種占位圖?分別在什么時(shí)候顯示,?

1.2 Target

當(dāng)我們調(diào)用 into() 方法,,傳入 ImageView 后,,Glide 會(huì)把 ImageView 轉(zhuǎn)化為 Target ,,下面我們來看下不同 Target 的作用。

1.2.1 ImageViewTarget

1. SizeDeterminer

ImageViewTarget 繼承了 ViewTarget ,,在 ViewTarget 中有一個(gè)用來獲取尺寸的 SizeDeterminer ,,SizeDeterminer 的 getSize() 方法拿到的尺寸,,是把 ImageView 的內(nèi)邊距 padding() 去掉后的尺寸。

在 Glide 中,,寬高分為請(qǐng)求寬高和原始寬高 ,,而 SizeDeterminer 拿到的尺寸就是請(qǐng)求寬高,Glide 會(huì)根據(jù)請(qǐng)求寬高對(duì)圖片進(jìn)行縮放操作,,以減少不必要的內(nèi)存消耗,。

2. OnPreDrawListener

當(dāng) Request 獲取 View 的尺寸失敗時(shí),ViewTarget 會(huì)通過 ViewTreeObserver 的 OnPreDrawListener 的回調(diào)來獲取 View 的尺寸,,然后再傳給 Request,。

3. setResource()

ImageViewTarget 主要有 BitmapImageViewTarget 和 DrawableImageViewTarget 兩個(gè)子類,它們兩個(gè)的區(qū)別就在于它們的 setResource() 方法,。

  • BitmapImageViewTarget

    setResource() 用的是 ImageView 的 setImageBitmap() 方法,;

  • DrawableImageViewTarget

    setResource() 用的是 ImageView 的 setImageDrawable() 方法;

1.2.2 RequestFutureTarget

1. submit()

FutureTarget 是一個(gè)實(shí)現(xiàn)了 Future 和 Target 接口的接口,,它只有一個(gè) RequestFutureTarget 子類 ,,當(dāng)我們用 submit() 方法獲取 Glide 加載好的圖片資源時(shí),,就是創(chuàng)建了一個(gè) RequestFutureTarget 。

2. Waiter

RequestFutureTarget 是用 wait/notify 的方式來實(shí)現(xiàn)等待和通知的,,這兩個(gè)是 Object 的方法,,Request 中有一個(gè) Waiter ,當(dāng) DecodeJob 加載到圖片后,,RequestFutureTarget 就會(huì)讓 Waiter 發(fā)出通知,,這時(shí)我們的 get() 方法就能獲取到返回值了。

這就是為什么我們用 RequestFutureTarget 的 get() 方法獲取圖片時(shí),,要把這個(gè)操作放在子線程運(yùn)行,。

1.2.3  CustomTarget

給不是 View 的 Target 加載圖片時(shí),Glide 都把它作為 CustomTarget ,。

1. PreloadTarget

預(yù)加載 Target 。

當(dāng)我們調(diào)用 preload() 選項(xiàng)預(yù)加載圖片時(shí),,Glide 會(huì)把圖片交給 PreloadTarget 處理,,當(dāng) PreloadTarget 接收到圖片資源后,就會(huì)讓 RequestManager 把該請(qǐng)求的資源釋放掉,。

因?yàn)椴恍枰却Y源加載完成,,所以我們?cè)谟?preload() 預(yù)加載圖片時(shí),不用像 submit() 一樣在子線程中執(zhí)行,。

2. AppWidgetTarget

桌面組件 Target ,。

當(dāng) AppWidgetTarget 接收到處理好的圖片資源后,會(huì)把它設(shè)置給 RemoteView ,,然后通過桌面組件管理器 AppWidgetManager 更新桌面組件,。

3. DelayTarget

GifTarget。

這是加載 Gif 圖片時(shí)要用到的 Target ,,關(guān)于 Glide 加載 Gif 圖片的流程在后面會(huì)講到,。

4. NotificationTarget

通知欄 Target 。

這個(gè) Target 有一個(gè) setBitmap 方法,,會(huì)把圖片設(shè)置給通知欄的 RemoteView ,,然后通過 NotificationManager 更新通知欄中的通知。

1.2.4 Target 相關(guān)問題

  1. ImageViewTarget 是用什么來獲取請(qǐng)求寬高的,?
  2. 為什么在用 submit() 獲取圖片時(shí),,要放在子線程中執(zhí)行?
  3. 使用 preload() 預(yù)加載圖片時(shí),,用的是哪個(gè) Target ,?該 Target 獲取到資源會(huì)后做什么?

1.3 Engine

下面我們來看一些與 Engine 相關(guān)的實(shí)現(xiàn),。

  • Engine 的作用
  • Key 的作用
  • Resource 的作用
  • BitmapPool

1.3.1 Engine 的作用

Engine 是 Glide 的圖片加載引擎,,是 Glide 中非常重要的一個(gè)類,,下面我們來看下 Engine 的作用。

1. load()

前面講到了當(dāng)我們調(diào)用 into() 方法時(shí),,就是間接調(diào)用了 Request.begin() 方法,,而 Request 的 begin() 方法又調(diào)用了 Engine 的 load() 方法。

在 load() 方法中,,Engine 會(huì)先用 EngineKeyFactory 創(chuàng)建資源標(biāo)識(shí)符 Key,,然后用這個(gè) Key 去內(nèi)存緩存中加載資源。

如果從內(nèi)存中找到了資源,,Engine 就會(huì)直接把資源回傳給 Resource,,如果沒有加載到資源,Engine 就會(huì)創(chuàng)建并啟動(dòng)新的 EngineJob 和解碼任務(wù) DecodeJob,。

2. EngineKeyFactory

EngineKeyFactory 是 Engine 中一個(gè)負(fù)責(zé)生產(chǎn) EngineKey 的工廠,,EngineKey 是引擎任務(wù)資源標(biāo)識(shí)符,關(guān)于什么是 Key 后面進(jìn)一步講,。

在 Engine 啟動(dòng)新的任務(wù)加載圖片前,,會(huì)先通過 EngineKeyFactory 創(chuàng)建一個(gè) EngineKey,然后讓 DecodeJob 把資源與 EngineKey 進(jìn)行綁定,,這里說的綁定,,其實(shí)就是把 model 放到 EngineKey 中。

3. 回收資源

Engine 中有一個(gè)資源回收器 ResourceRecycler ,,Resource 接口中有一個(gè) recycle() 方法,,關(guān)于 Resource 我們后面再講。

這里只要知道,,當(dāng) SingleRequest 被清除,,比如在 into() 方法中發(fā)現(xiàn) Target 已經(jīng)有對(duì)應(yīng)的 Request 時(shí),Request 就會(huì)讓 Engine 釋放資源,,具體做釋放資源操作的就是 ResourceRecycler,。

4. 磁盤緩存提供器

LazyDiskCacheProvider 是 Engine 中的一個(gè)靜態(tài)內(nèi)部類,是磁盤緩存 DiskCache 的提供器,,DiskCache 是一個(gè)接口,,關(guān)于 DiskCache 的實(shí)現(xiàn)我們后面再講。

5. 啟動(dòng)新的解碼任務(wù)

當(dāng) Engine 從內(nèi)存中找不到對(duì)應(yīng)的 Key 的資源時(shí),,就會(huì)啟動(dòng)新的解碼任務(wù),。

Engine 會(huì)用加載任務(wù)工廠 EngineJobFactory 構(gòu)建一個(gè)加載任務(wù) EngineJob,然后再構(gòu)建一個(gè)解碼任務(wù) DecodeJob,。

EngineJob 這個(gè)名字看起來很霸氣,,但是實(shí)際上它并沒有做什么事情,它只是 Engine 與 DecodeJob 之間溝通的橋梁。

當(dāng)構(gòu)建了 EngineJob 和 DecodeJob 后,,Engine 就會(huì)把 DecodeJob 提交到線程池 GlideExecutor 中,。

1.3.2 Key

前面講到了 Engine 會(huì)通過 EngineKeyFactory 創(chuàng)建資源標(biāo)識(shí)符 Key ,那什么是 Key ,?

Key 是 Glide 中的一個(gè)接口,,是圖片資源的標(biāo)識(shí)符。

1. 避免比較有誤

Glide 的內(nèi)存緩存和磁盤緩存用的都是 Glide 自己實(shí)現(xiàn)的 LruCache,,LruCache 也就是最近最少使用緩存算法(Least Recently Used),,LruCache 中有一個(gè) LinkedHashMap ,這個(gè) HashMap 的 Key 就是 Key 接口,,而 Value 則是 Resource 接口,。

在用對(duì)象作為 HashMap 的 Key 時(shí),要重寫 equals() 和 hashCode() 方法,。

如果不重寫這兩個(gè)方法,,那么當(dāng)兩個(gè) Key 的內(nèi)存地址不同,但是實(shí)際代表的資源相同時(shí),,使用父類 Object的 hasCode() 直接用內(nèi)存地址做比較,,那么結(jié)果會(huì)是不相等。

此外 Object 的 equals() 方法也是拿內(nèi)存地址作比較,,所以也要重寫。

比如下面就是 ResourceCacheKey 的 equals() 判斷邏輯,。

2. Key 實(shí)現(xiàn)類

下面是幾個(gè)實(shí)現(xiàn)了 Key 接口的類,。

  • DataCacheKey

    原始圖片數(shù)據(jù)標(biāo)識(shí)符。

  • ResourceCacheKey

    處理后的圖片資源標(biāo)識(shí)符,。

  • AndroidResourceSignature

    Android 資源標(biāo)識(shí)符,。當(dāng)我們傳入 into() 方法的圖片是 R.drawable.xxx 時(shí),Glide 就會(huì)把它封裝為 AndroidResourceSignature ,。

  • ObjectKey

    通用資源標(biāo)識(shí)符,。

    可以說除了 App 自帶的 Android 資源以外的圖片資源都會(huì)用 ObjectKey 作為標(biāo)識(shí)符,比如本地圖片文件,。

  • EngineKey

    引擎資源標(biāo)識(shí)符,。

    這個(gè) Key 是 Engine 對(duì)其他 Key 的封裝,這時(shí)傳進(jìn)來的 Key 是以簽名(Signature)的身份存在 EngineKey 中的,。

1.3.3 Resource

前面講到了 Engine 會(huì)通過 ResourceRecycler 來回收資源,,而 ResourceRecycler 調(diào)用了 Resource 的 recycle() 方法。

可能你想起來 Bitmap 就有一個(gè)可以回收?qǐng)D片內(nèi)存的 recycle() 方法,,沒錯(cuò),,Glide 回收 Bitmap 的方式就是用的 Bitmap 自帶的 recycle() 方法,但是這個(gè)過程又比這復(fù)雜一些,。

Resource 是一個(gè)接口,,其中一個(gè)實(shí)現(xiàn)類是 BitmapResource ,,也就是位圖資源,比如網(wǎng)絡(luò)圖片就會(huì)轉(zhuǎn)化為 BitmapResource,。

在 BitmapResource 中有一個(gè)位圖池 BitmapPool,,這是 Glide 用來復(fù)用 Bitmap 的一個(gè)接口,具體的實(shí)現(xiàn)類是 LruBitmapPool ,。

在 BitmapResource 的 recycle() 方法中,,會(huì)把對(duì)應(yīng)的 Bitmap 通過 put() 方法放到 BitmapPool 中,關(guān)于 BitmapPool 在講 Glide 緩存原理時(shí)會(huì)進(jìn)一步講,。

1.3.4 Engine 相關(guān)問題

  1. Engine 的 load() 方法首先會(huì)做什么,?
  2. 為什么 Key 要重寫 hashCode() 和 equals() 方法?
  3. 負(fù)責(zé)回收 Resource 的是哪個(gè)類,?
  4. 加載 Drawable 資源時(shí),,會(huì)轉(zhuǎn)化為哪種 Key?

1.4 DecodeJob

前面講到了 Engine 在緩存中找不到資源時(shí),,就會(huì)創(chuàng)建新的加載任務(wù) EngineJob 和新的解碼任務(wù) DecodeJob ,,然后讓 EngineJob 啟動(dòng) DecodeJob。

DecodeJob 實(shí)現(xiàn)了 Runnable 接口,,EngineJob 啟動(dòng) DecodeJob 的方式就是把它提交給 GlideExecutor,,如果我們沒有調(diào)整磁盤緩存策略的話,那默認(rèn)用的就是 diskCacheExecutor ,,關(guān)于 GlideExecutor 在第 4 大節(jié)會(huì)講,,下面我們先看下 DecodeJob 的實(shí)現(xiàn)。

1.4.1 runWrapped()

DecodeJob 的 run() 方法只是對(duì) runWrapped() 可能遇到的異常進(jìn)行了捕獲,,而 runWrapped() 方法會(huì)根據(jù)不同的運(yùn)行理由 RunReason 運(yùn)行不同的數(shù)據(jù)生成器,。

1. 三種運(yùn)行理由

runWrapped() 會(huì)根據(jù)下面三種運(yùn)行理由來執(zhí)行解碼任務(wù)。

  • INITAILIZE

    從緩存中獲取數(shù)據(jù)并解碼,;

  • SWITCH_TO_SOURCE_SERVICE

    從來源獲取數(shù)據(jù)后再進(jìn)行解碼,;

  • DECODE_DATA

    當(dāng)獲取數(shù)據(jù)的線程與 DecodeJob 的線程不同時(shí),比如使用了 OkHttp-Integration 時(shí),,DecodeJob 會(huì)直接對(duì)數(shù)據(jù)進(jìn)行解碼,;

2. 初始化

當(dāng)運(yùn)行理由為默認(rèn)狀態(tài) INITIALIZE 時(shí),DecodeJob 會(huì)從磁盤中獲取圖片數(shù)據(jù)并進(jìn)行解碼,。

3. 從來源獲取數(shù)據(jù)

當(dāng) DecodeJob 從緩存中獲取不到數(shù)據(jù)時(shí),,就會(huì)把運(yùn)行理由改為 SWITCH_TO_SOURCE_SERVICE ,也就是從來源獲取數(shù)據(jù),,然后運(yùn)行來源數(shù)據(jù)生成器 SourceGenerator ,。

4. 對(duì)檢索到的數(shù)據(jù)進(jìn)行解碼

DecodeJob 通過數(shù)據(jù)生成器獲取到數(shù)據(jù)后,就會(huì)調(diào)用 decodeFromRetrievedData() 方法來對(duì)檢索到的數(shù)據(jù)進(jìn)行解碼。

1.4.2 DecodeJob 數(shù)據(jù)獲取流程

在 DecodeJob 的 getNextStage() 方法中,,會(huì)根據(jù)當(dāng)前的解碼步驟 stage 來判斷進(jìn)行什么操作,。

DecodeJob 把提取數(shù)據(jù)分為了 6 個(gè)階段,這 6 個(gè)階段是 Stage 枚舉類中的值,。

1. INITIALIZE

初始化,。

當(dāng)解碼處于這個(gè)階段時(shí),DecodeJob 會(huì)根據(jù)磁盤緩存策略,,判斷是否要從磁盤緩存中獲取處理過的圖片資源,,是的話就用 ResourceCacheGenerator 獲取圖片資源,當(dāng)用 ResourceCacheGenerator 獲取到 Resource 后,,就會(huì)開始對(duì)資源進(jìn)行解碼,。

如果磁盤緩存策略設(shè)定了不從緩存中獲取 Resource,那就會(huì)切換到 RESOURCE_CACHE 階段,。

2. RESOURCE_CACHE

從緩存中獲取處理過的圖片資源,。

當(dāng)解碼處于這個(gè)階段時(shí),DecodeJob 會(huì)根據(jù)磁盤緩存策略,,判斷是否要從磁盤緩存中獲取未處理過的圖片原始數(shù)據(jù),,是的話就用 DataCacheGenerator 獲取圖片數(shù)據(jù)。

3. DATA_CACHE

從緩存中獲取原始數(shù)據(jù),。

如果磁盤緩存策略設(shè)定了不獲取緩存中的圖片資源和原始數(shù)據(jù) ,,又或者是獲取不到數(shù)據(jù),DecodeJob 那就會(huì)切換到 DATA_CACHE 階段,。

如果我們?cè)诩虞d圖片時(shí)調(diào)用了 onlyRetrieveFromCache(true) ,,那么 DecodeJob 就會(huì)不會(huì)切換到 SOURCE 階段從來源獲取數(shù)據(jù),而是會(huì)切換到 FINISH 階段結(jié)束數(shù)據(jù)獲取流程,。

否則就會(huì)切換到 SOURCE 階段。

4. SOURCE

從圖片來源獲取原始數(shù)據(jù),。

如果 DecodeJob 在 RESOURCE_CACHE 和 DATA_CACHE 階段都沒有拿到圖片數(shù)據(jù),,那就會(huì)用 SourceGenerator 從圖片來源獲取圖片數(shù)據(jù)。

5. ENCODE

編碼,。

當(dāng)磁盤緩存策略設(shè)定了要對(duì)圖片資源進(jìn)行緩存時(shí),,那么在獲取到數(shù)據(jù)后,DecodeJob 就會(huì)用 ResourceDecoder 對(duì)資源進(jìn)行編碼,,也就是把圖片放到磁盤緩存中,。

6. FINISH

結(jié)束。

1.4.3 三種數(shù)據(jù)生成器

當(dāng) DecodeJob 切換階段后,,會(huì)調(diào)用 getNextGenerator() 切換不同階段對(duì)應(yīng)的生成器,,這里說的生成器,指的是 DataFetcherGenerator 接口。

DataFetcherGenerator 不是像名字說的那樣用來創(chuàng)建 DataFetcher 的,,DataFetcherGenerator 與 DataFetcher 是通過 ModelLoader 來關(guān)聯(lián)的,。

DataFetcherGenerator 會(huì)通過 ModelLoader 構(gòu)建數(shù)據(jù)封裝對(duì)象 LoadData ,然后通過 LoadData 中的 DataFetcher 來加載數(shù)據(jù),。

LoadData 是 ModelLoader 的內(nèi)部類,,它有來源標(biāo)識(shí)符 Key 和 DataFetcher 兩個(gè)字段。

在 ModelLoader 中最重要的就是 buildLoadData() 方法,,不同類型的 Model 對(duì)應(yīng)的 ModelLoader 所創(chuàng)建出來的 LoadData() 也不同,。

下面我們來看下 DataFetcherGenerator ,這個(gè)接口中最重要的方法是 startNext() ,,具體實(shí)現(xiàn)了這個(gè)接口有下面三個(gè)類,。

  • SourceGenerator

    來源數(shù)據(jù)生成器。

  • DataCacheGenerator

    原始緩存數(shù)據(jù)生成器,。

  • ResourceCacheGenerator

    緩存資源生成器,。

以 SourceGenerator 為例,我們來看下 startNext() 方法的處理流程,。

1. 是否獲取到了需要緩存的數(shù)據(jù)

當(dāng) SourceGenerator 加載完數(shù)據(jù)后,,會(huì)再次進(jìn)入 startNext() 方法,這時(shí)就獲取到了需要緩存的數(shù)據(jù),。

2. 是否保存原始數(shù)據(jù)

如果磁盤緩存策略設(shè)定了要保存圖片的原始數(shù)據(jù),,就用數(shù)據(jù)提取器加載數(shù)據(jù),否則就直接把圖片加載給 Target ,。

3. 加載數(shù)據(jù)

當(dāng)需要保存原始數(shù)據(jù)或數(shù)據(jù)有加載路徑時(shí),,SourceGenerator 就會(huì)根據(jù) Model 的類型,使用對(duì)應(yīng)的 DataFetcher 來提取數(shù)據(jù),,比如從網(wǎng)絡(luò)上下載圖片,。

4. 是否保存原始數(shù)據(jù)

當(dāng) SourceGenerator 獲取到數(shù)據(jù)后,會(huì)再次判斷是否要保存原始數(shù)據(jù),,否則就直接把圖片加載給 Target ,。

5. 編碼

當(dāng) SourceGenerator 從 DataFetcher 中拿到數(shù)據(jù)后,會(huì)再走一遍 startNext() 方法,,然后用編碼器 Encoder 對(duì)數(shù)據(jù)進(jìn)行編碼,,也就是把圖片放到磁盤緩存中。

6. 從磁盤中獲取數(shù)據(jù)

當(dāng) SourceGenerator 把數(shù)據(jù)保存到磁盤后,,不會(huì)直接加載圖片,,而是從磁盤中拿這張圖片,然后再進(jìn)行加載,。

1.4.4 onResourceDecoded()

當(dāng) DecodeJob 調(diào)用 ResourceDecoder 的 decode() 方法,,并且獲取到編碼結(jié)果后,,會(huì)調(diào)用 onResourceDecoded() 方法應(yīng)用變換選項(xiàng)以及初始化編碼管理器。

1. 應(yīng)用變換選項(xiàng)

對(duì)于處理過的 Resource,,onResourceDecoded() 不會(huì)再次進(jìn)行變換,,否則就會(huì)對(duì)圖片進(jìn)行變換操作。

2. 回收?qǐng)D片資源

當(dāng)對(duì)資源應(yīng)用了變換選項(xiàng)后,,DecodeJob 會(huì)把原來的資源回收掉,,因?yàn)檫@個(gè)資源接下來也用不上了。

3. 緩存變換后圖片資源

onResourceDecoded() 方法中,,會(huì)根據(jù)磁盤緩存策略判斷是否要對(duì)資源進(jìn)行編碼,,如果要進(jìn)行編碼的話,會(huì)根據(jù)不同的編碼策略創(chuàng)建不同的 Key ,。

Glide 有 SOURCE 和 TRANSFORMED 兩種編碼策略,,分別代表對(duì)原始數(shù)據(jù)進(jìn)行編碼和對(duì)變換后資源進(jìn)行編碼。

  • SOURCE

    GIF 編碼器 GifDrawableEncoder 中用的編碼策略,;

  • TRANSFORMED

    位圖編碼器 BitmapEncoder 中用的編碼策略,;

4. 初始化編碼管理器

創(chuàng)建好 Key 后不會(huì)直接對(duì)圖片進(jìn)行編碼,而是會(huì)修改編碼管理器的 Key ,,等到轉(zhuǎn)碼完成后再用 ResourceEncoder 進(jìn)行編碼,。

1.4.5 DecodeJob 相關(guān)問題

  1. DecodeJob 會(huì)根據(jù)哪些理由來執(zhí)行任務(wù)?
  2. DecodeJob 提取數(shù)據(jù)的過程分為哪幾個(gè)階段,?
  3. DataFetcherGenerator 有哪些實(shí)現(xiàn)類,?
  4. Glide 有幾種編碼策略?

2. 六步加載圖片

看完了解碼任務(wù)啟動(dòng)流程,,下面我們來看下當(dāng) DecodeJob 獲取到圖片數(shù)據(jù)后是怎么處理這些數(shù)據(jù)的,,在文章的開頭已經(jīng)講過 Glide 解碼大致的 5 步,這里再補(bǔ)充一個(gè),,就是在把圖片加載到 Target 后,,DecodeJob 會(huì)通過 ResourceEncoder 把圖片保存到本地。

其中關(guān)于 Target 在 1.2 小節(jié)已經(jīng)講過,,下面就不再多講了,,我們來看下其他的對(duì)象。

Glide 對(duì)圖片解碼的過程涉及下面 6 個(gè)概念,。

  1. 數(shù)據(jù)來源(Model)

  2. 原始數(shù)據(jù)(Data)

  3. 資源(Resource)

  4. 變換后資源(TransformedResource)

  5. 轉(zhuǎn)碼后資源(TranscodedResource)

  6. 目標(biāo)(Target)

1. 數(shù)據(jù)來源(Model)

Glide 會(huì)以 Model 的形式封裝圖片來源 ,,Model 可以是 URL,、本地文件和網(wǎng)絡(luò)圖片等類型,。

2. 原始數(shù)據(jù)(Data)

Glide 把數(shù)據(jù)源轉(zhuǎn)換為Model 后,會(huì)把它加工成原始數(shù)據(jù) Data ,,一般就是輸入流 InputStream ,,Glide 會(huì)把這些輸入流封裝為 Data ,,而 ModelLoader 則負(fù)責(zé)從 Data 獲取原始數(shù)據(jù)。

3. 資源(Resource)

獲取到原始數(shù)據(jù)后,,Glide 會(huì)用資源解碼器 ResourceDecoder 對(duì)原始數(shù)據(jù)進(jìn)行解碼,,比如把輸入流 InputStream 解碼為 Bitmap,解碼后的資源就是 Resource ,。

4. 變換后資源(TransformedResource)

Glide 會(huì)根據(jù)我們的變換選項(xiàng)處理 Resource ,,比如用 centerCrop() 裁剪就是一種變換,變換后的 Resource 就叫 TransformedResource ,,負(fù)責(zé)轉(zhuǎn)換的就是 Transformation ,。

5. 轉(zhuǎn)碼后資源(TranscodedResource)

Glide 除了能加載靜態(tài)圖片,還能加載 Gif 動(dòng)態(tài)圖,,解碼后的 Bitmap 和 Gif 的類型不是統(tǒng)一的,,為了統(tǒng)一處理靜態(tài)和動(dòng)態(tài)圖片,Glide 會(huì)把 Bitmap 轉(zhuǎn)換為 GlideBitmapDrawable ,,而負(fù)責(zé)轉(zhuǎn)碼的角色則是 ResourceTranscoder ,。

6. 目標(biāo)(Target)

Glide 最終會(huì)把圖片顯示到目標(biāo) Target 上,比如 ImageView 對(duì)應(yīng)的就是 ImageViewTarget ,。

2.1 ModelLoader

ModelLoader 是一個(gè)接口,,負(fù)責(zé)創(chuàng)建 LoadData ,它有兩個(gè)泛型參數(shù) Model 和 Data,。

  • Model

    代表圖片來源的類型,,比如圖片的網(wǎng)絡(luò)地址的 Model 類型為 String ;

  • Data

    代表圖片的原始數(shù)據(jù)的類型,,比如網(wǎng)絡(luò)圖片對(duì)應(yīng)的類型為 InputStream ,;

1. Factory

在 DataFetcherGenerator 獲取圖片數(shù)據(jù)時(shí),會(huì)調(diào)用 ModelLoaderRegistry 的 getModelLoaders() 方法,,這個(gè)方法中會(huì)根據(jù) model 的類型用 MultiModelLoaderFactory 生成對(duì)應(yīng)的 ModelLoader,,比如能夠解析字符串的 ModelLoader 就有 7 個(gè),關(guān)于 ModelLoaderRegistry 在后面講 Glide 配置的時(shí)候會(huì)講到,。

此外每一個(gè) ModelLoader 的實(shí)現(xiàn)類中都定義了一個(gè)實(shí)現(xiàn)了 ModelLoaderFactory 接口的靜態(tài)內(nèi)部類 ,。

2. handles()

一個(gè) Model 對(duì)應(yīng)這么多 ModelLoader,每個(gè) ModelLoader 加載數(shù)據(jù)的方式都不同,,這時(shí)候就要用 handles() 方法了,。

ModelLoader 接口有 handles() 和 buildLoadData() 兩個(gè)方法,handles() 用于判斷某個(gè) Model 是否能被自己處理,,比如 HttpUriLoader 的 handles() 會(huì)判斷傳進(jìn)來的字符串是否以 http 或 https 開頭,,是的話則可以處理。

3. buildLoadData()

ModelLoader 之間是存在嵌套關(guān)系的,,比如 HttpUriLoader 的 buildLoadData() 方法就是調(diào)用的 HttpGlideUrlLoader 的 buildLoadData() 方法,,HttpGlideUrlLoader 會(huì)創(chuàng)建一個(gè) HttpUrlFetcher ,,然后把它放到 LoadData() 中。

LoadData 是 ModelLoader 中定義的一個(gè)類,,它只是放置了圖片來源的 Key 和要用來提取數(shù)據(jù)的 DataFetcher ,,沒有其他方法。

2.2 ResourceDecoder

DataFetcherGenerator 使用 ModelLoader 構(gòu)建完數(shù)據(jù)后,,就會(huì)用 DataRewinder 對(duì)數(shù)據(jù)進(jìn)行重繞,,也就是重置數(shù)據(jù),比如 InputStreamRewinder 就會(huì)調(diào)用 RecyclableBufferedInputStream 的 reset() 方法重置輸入流對(duì)應(yīng)的字節(jié)數(shù)組的位置,。

ResourceDecoder 是一個(gè)接口,,有非常多的實(shí)現(xiàn)類,比如網(wǎng)絡(luò)圖片對(duì)應(yīng)的解碼器為 StreamBitmapDecoder ,,StreamBitmapDecoder 的 decode() 方法調(diào)用了降采樣器 Downsampler 的 decode() 方法,,下圖是 Downsampler 的解碼邏輯。

1. 設(shè)置目標(biāo)寬高

除非我們通過 override() 方法把尺寸改為 Target.SIZE_ROGINAL ,,否則 Glide 默認(rèn)會(huì)把 ImageView 的大小作為加載圖片的目標(biāo)寬高,。

2. 計(jì)算縮放后寬高

根據(jù)不同的變換選項(xiàng)計(jì)算縮放后寬高。

3. 創(chuàng)建空 Bitmap

根據(jù)計(jì)算后的目標(biāo)寬高創(chuàng)建一個(gè)空的 Bitmap ,。

4. 使用 BitmapFactory 解碼

Downsampler 的解碼方式用的是 ImageReader 的 decodeBitmap() 方法,,而 ImageReader 又調(diào)用了 BitmapFactory 的 decodeStream() 方法,BitmapFactory 最終調(diào)用的是 SkImageDecoder 的 decode() 方法,。

5. 把 Bitmap 放入 BitmapPool 中

在前面講 Resource 的時(shí)候講到了 BitmapResource 中有一個(gè) BitmapPool,,這個(gè) BitmapPool 是由 Downsampler 傳過去的,而 Downsampler 的 BitmapPool 是由 Glide 創(chuàng)建并傳進(jìn)來的,。

2.3 Transformation

Transformation 是一個(gè)接口,,它有一個(gè) transform() 方法,這個(gè)方法是在 DecodeJob 中調(diào)用的,,當(dāng) DecodeJob 發(fā)現(xiàn)數(shù)據(jù)源不是緩存中的 Resource 時(shí),,就會(huì)調(diào)用變換選項(xiàng)的 transform() 方法。

Transformation 的其中一個(gè)實(shí)現(xiàn)類是 BitmapTransformation,,我們平時(shí)調(diào)用的 centerCrop() 就是 BitmapTransformation 的子類,,centerCrop() 選項(xiàng)對(duì)應(yīng)的是 CenterCrop 類,它實(shí)現(xiàn)了 Transformation 接口,,具體的變換實(shí)現(xiàn)在 TransformationUtils 中,。

1. Matrix

以 centerCrop() 為例,TransformationUtils 的 centerCrop() 方法會(huì)先創(chuàng)建一個(gè) Matrix 矩陣,,然后根據(jù)傳進(jìn)來的 Bitmap 計(jì)算 Matrix 的縮放比例和平移坐標(biāo),。

2. drawBitmap()

配置好 Matrix 后,就會(huì)根據(jù)目標(biāo)寬高創(chuàng)建一個(gè)空的目標(biāo) Bitmap ,,然后把原始 Bitmap,、目標(biāo) Bitmap 和 Matrix 傳給 Canvas 的 drawBitmap() 方法,然后返回 Canvas 處理好的圖片,。

2.4 ResouceTranscoder

ResourceTranscoder 是一個(gè)接口,,是 Glide 中的資源轉(zhuǎn)碼器,它有兩個(gè)泛型參數(shù) Z 和 R ,,分別代表需要進(jìn)行原始類型和轉(zhuǎn)碼目標(biāo)類型,。

比如 BitmapDrawableTranscoder 的原始類型是 Bitmap,轉(zhuǎn)碼目標(biāo)類型是 BitmapDrawable,,在BitmapDrawableTranscoder 的 transcode() 方法中,,會(huì)把 Bitmap 轉(zhuǎn)換為 BitmapDrawable ,以便 Target 進(jìn)行處理,。

2.5 ResourceEncoder

ResourceEncoder 是一個(gè)接口,,是 Glide 中的資源編碼器,ResourceEncoder 有好幾個(gè)實(shí)現(xiàn)類,,比如網(wǎng)絡(luò)圖片對(duì)應(yīng)的編碼器為 StreamEncoder,。

在轉(zhuǎn)碼完成后,DecodeJob 會(huì)先把圖片加載到 Target 中,,然后用 ResourceEncoder 對(duì)圖片進(jìn)行編碼,,比如 StreamEncoder 的編碼操作就是把輸入流 InputStream 轉(zhuǎn)化為圖片文件,然后保存到本地,。

2.6 圖片加載相關(guān)問題

  1. 圖片加載分為哪幾步,?
  2. ModelLoader 有哪些泛型參數(shù)?分別代表什么,?
  3. ResourceDecoder 會(huì)用哪個(gè)類進(jìn)行解碼,?最終進(jìn)行解碼的哪個(gè)類?
  4. 真正進(jìn)行變換操作的是哪個(gè)類,?變換操作使用了哪些類,?
  5. Glide 怎么對(duì)圖片數(shù)據(jù)進(jìn)行編碼?

3. Glide 緩存原理

Glide 使用了三級(jí)緩存機(jī)制,,圖片的緩存分為內(nèi)存,、磁盤和來源,也就是從內(nèi)存獲取不到圖片時(shí),,再去磁盤獲取圖片,,從磁盤獲取不到圖片時(shí),再從圖片來源獲取圖片,。

三級(jí)緩存的優(yōu)勢(shì)在于節(jié)省流量和內(nèi)存,,如果不用三級(jí)緩存,每次都從服務(wù)端獲取圖片的話,,圖片消耗的流量就會(huì)非常多,,如果把所有圖片都放在內(nèi)存的話,,那就有可能發(fā)生 OOM 。

下面我們來看下 Glide 的內(nèi)存緩存原理,、磁盤緩存原理和磁盤緩存策略,。

3.1 Glide 內(nèi)存緩存原理

前面提到 Engine 的 load() 方法會(huì)先在內(nèi)存緩存中查找 Key 對(duì)應(yīng)的資源,沒有的話再啟動(dòng)新的解碼任務(wù),。

這里說的內(nèi)存緩存就是 MemoryCache,,MemoryCache 是一個(gè)接口,它的實(shí)現(xiàn)類是 LruResourceCache,。

LruResourceCache 不僅實(shí)現(xiàn)了 MemoryCache 接口,,而且還是 LruCache 的子類,具體的內(nèi)存緩存實(shí)現(xiàn)是在 LruCache 中,。

在 LruCache 的 put() 方法中,,首先會(huì)判斷要保存的元素大小是否大于緩存最大值,如果是的話,,則不進(jìn)行保存,,如果不是的話,則把當(dāng)前容量加上元素的大小,,并把該元素放入緩存,。

LruCache 比較特別的就是它的 trimToSize() 方法和 LinkedHashMap 的 accessOrder 屬性。

1. trimToSize()

LruCache 在用 put() 方法保存新的元素時(shí),,它會(huì)通過 trimToSize() 方法移除最近最少使用的元素,。

2. accessOrder

LruCache 中是用 LinkedHashMap 保存數(shù)據(jù)的,并且這個(gè) LinkedHashMap 的 accessOrder 的值為 true,,也就是每一次獲取 LinkedHashMap 中的元素時(shí),,這個(gè)元素都會(huì)被移到鏈表的尾端。

3.2 Glide 磁盤緩存原理

Glide 是用 DiskCache 保存圖片文件的,,DiskCache 是一個(gè)接口,,這個(gè)接口中還定義了 Factory 和 Writer 兩個(gè)接口,Writer 只是對(duì) ResourceEncoder 的封裝,。

下面我們就來看看 DiskCache 和 DiskCache.Factory 的具體實(shí)現(xiàn),。

3.2.1  DiskLruCache

DiskCache 有兩個(gè)實(shí)現(xiàn)類, DiskCacheAdapter 和 DiskLruCacheWrapper,,DiskCacheAdapter 只是一個(gè)空實(shí)現(xiàn),。

從名字可以看得出來 DiskLruCacheWrapper 是對(duì) DiskLruCache 的封裝,具體的實(shí)現(xiàn)是在 DiskLruCache 中,,DataCacheGenerator 和 ResourceCacheGenerator 都是用的 DiskLruCache 來獲取磁盤緩存數(shù)據(jù)的,。

1. Entry

和 LruCache 一樣,DiskLruCache 中也有一個(gè) LinkedHashMap ,這個(gè) HashMap 的 Key 的類型為 String,,Value 的類型為 Entry,,從緩存中獲取到的圖片文件會(huì)放在 Entry的 cleanFiles 字段中。

2. Editor

當(dāng)圖片加載進(jìn)入編碼階段時(shí),,DecodeJob 會(huì)通過編碼管理器調(diào)用 DiskLruCacheWrapper 的 put() 方法保存圖片文件,。

在 DiskLruCacheWrapper 的 put() 方法中,會(huì)通過 DiskCache 的緩存編輯器 Editor 獲取圖片文件,,獲取到圖片文件后,就會(huì)用 Writer 把文件寫入本地,,寫完后再調(diào)用 Editor 的 commit() 方法,,把清理緩存的回調(diào)提交到清理線程池中。

3. 清理資源

DiskLruCache 中有一個(gè)執(zhí)行清理資源任務(wù)的線程池,,線程池的線程數(shù)最多為 1,,

這個(gè)線程池要執(zhí)行的任務(wù)為 cleanupCallback 回調(diào),這個(gè)回調(diào)會(huì)執(zhí)行 trimToSize() 方法,,為的就是把最近最少使用的文件清除掉,。

3.2.2  DiskCache.Factory

在 DiskCache 中有一個(gè) Factory 工廠接口,這個(gè)接口用在了 Engine 的 LazyDiskCacheProvider 中,。

在 Factory 接口中,,定義了默認(rèn)的磁盤緩存大小為 250M,默認(rèn)的緩存目錄名稱為 "image_manager_disk_cache" ,。

Factory 主要有下面 2 個(gè)實(shí)現(xiàn)類,。

  • ExternalPreferredCacheDiskCacheFactory

    用的是 getExternalCacheDir() 。

    對(duì)應(yīng)的目錄是 /data/user/0/包名/cache/image_manager_disk_cache,。

  • InternalCacheDiskCacheFactory

    用的是 context.getCacheDir() ,。

    對(duì)應(yīng)的目錄是 /data/user/0/包名/cache 。

默認(rèn)情況下 Glide 用的是 InternalCacheDiskCacheFactory ,,如果想把圖片放在外部緩存目錄的話,,可以在自定義的 GlideModule 設(shè)置 DiskCache 。

3.3  Glide 磁盤緩存策略

在加載圖片時(shí),,我們可以用 diskCacheStratgy() 方法設(shè)置圖片在磁盤的緩存策略,,這個(gè)選項(xiàng)傳入的參數(shù)類型為抽象類 DiskCacheStrategy。

磁盤緩存策略涉及到 Glide 的數(shù)據(jù)源類型 DataSource 和編碼策略 EncodeStratefy,,編碼策略前面講過了,,下面我們先來看看數(shù)據(jù)源 DataSource。

3.3.1 五種數(shù)據(jù)源

Glide 中定義了下面 5 種數(shù)據(jù)源 DataSource,。

  • LOCAL

    設(shè)備上有的數(shù)據(jù),,比如 App 內(nèi)置的 Drawable 也屬于 LOCAL ;

  • REMOTE

    從服務(wù)端拿到的數(shù)據(jù);

  • DATA_DISK_CACHE

    從緩存中取出來的原始數(shù)據(jù),;

  • RESOURCE_DISK_CACHE

    從緩存中取出來的圖片資源,;

  • MEMORY_CACHE

    從內(nèi)存緩存中取出來的數(shù)據(jù);

3.3.2 四個(gè)抽象方法

DiskCacheStrategy 有下面 4 個(gè)抽象方法,,這個(gè) 4 個(gè)方法的返回值都是布爾值,。

  • isDataCacheable()
  • isResourceCacheable()
  • decodeCachedResource()
  • decodeCacheData()
1. isDataCacheable()

是否保存圖片的原始數(shù)據(jù)。

DecodeJob 中用到的 SourceGenerator 在從圖片來源獲取到數(shù)據(jù)后,,會(huì)根據(jù)這個(gè)方法判斷是否保存圖片的原始數(shù)據(jù),。

2. isResourceCacheable()

是否保存解碼后的圖片數(shù)據(jù)。

當(dāng)資源解碼器對(duì)圖片數(shù)據(jù)進(jìn)行解碼后,,DecodeJob 就會(huì)根據(jù)這個(gè)方法的返回值決定是否保存該 Resource ,。

3. decodeCachedResource()

是否對(duì)緩存的解碼后的圖片數(shù)據(jù)進(jìn)行解碼。

在 DecodeJob 的 getNextStage() 中,,會(huì)根據(jù)這個(gè)方法的返回值判斷,,如果返回值為 false,意味著跳過 RESOURCE_CACHE 步驟,,也就是不對(duì)緩存中處理過的圖片資源進(jìn)行處理,。

4. decodeCachedData()

是否對(duì)緩存的原始數(shù)據(jù)進(jìn)行解碼。

在 DecodeJob 的 getNextStage() 方法中,,會(huì)根據(jù)這個(gè)方法的返回值判斷,,如果該值為 false,意味著跳過 DATA_CACHE 步驟,,也就是不對(duì)緩存中的原始圖片數(shù)據(jù)進(jìn)行處理,。

4.3.2 五種緩存策略

Glide 定義好的磁盤緩存策略有下面 5 種,默認(rèn)為 AUTOMATIC,。

  • AUTOMATIC
  • ALL
  • NONE
  • RESOURCE
  • DATA
1. AUTOMATIC
  • isDataCacheable()

    只保存網(wǎng)絡(luò)圖片的原始數(shù)據(jù),;

  • isResourceCacheable()

    只保存數(shù)據(jù)源為 DATA_DISK_CACHE 或 LOCAL ,并且編碼策略為 TRANSFORMED 的圖片資源,;

  • decodeCachedResource()

    true,;

  • decodeCachedData()

    true;

2. ALL
  • isDataCacheable()

    只保存網(wǎng)絡(luò)圖片的原始數(shù)據(jù),;

  • isResourceCacheable()

    不保存數(shù)據(jù)源為 RESOURCE_DISK_CACHE 和 MEMORY_CACHE 的圖片資源,;

  • decodeCachedResource()

    true;

  • decodeCachedData()

    true,;

3. DATA
  • isDataCacheable()

    不保存數(shù)據(jù)源為 DATA_DISK_CACHE 或 MEMORY_CACHE 的圖片資源,;

  • isResourceCacheable()

    false;

  • decodeCachedResource()

    false,;

  • decodeCachedData()

    true,;

4. RESOURCE
  • isDataCacheable()

    false;

  • isResourceCacheable()

    不保存數(shù)據(jù)源為 RESOURCE_DISK_CACHE 和 MEMORY_CACHE 的圖片資源;

  • decodeCachedResource()

    true,;

  • decodeCachedData()

    false,;

5. NONE

所有方法的返回值都為 false。

3.4 BitmapPool

1. 減少 Bitmap 占用的內(nèi)存

BitmapResource 的 BitmapPool 用的就是 GlideBuilder 中的 BitmapPool,,Downsampler 在解碼后,,會(huì)把圖片放入 BitmapPool 中,當(dāng) BitmapResource 被回收時(shí),,也會(huì)把 Bitmap 放到 BitmapPool 中,。

具體需要用到 BitmapPool 中的 Bitmap 的地方在 TransformationUtils 中,TransformationUtils 在進(jìn)行變換前會(huì)從 BitmapPool 中獲取之前保存的 Bitmap,。

之所以要這么做,,是因?yàn)槊恳淮巫儞Q都需要?jiǎng)?chuàng)建一個(gè) Bitmap ,BitmapPool 就是為了復(fù)用這個(gè) Bitmap 占用的內(nèi)存,,這樣下次要做變換操作時(shí),,可以用同一個(gè) Bitmap 就進(jìn)行復(fù)用,,以減少內(nèi)存使用,。

比如對(duì)于 RecyclerView 中的圖片,它們的大小是一樣的,,沒必要在變換時(shí)為每張圖片都創(chuàng)建一個(gè)新的 Bitmap,。

2. LruPoolStrategy

BitmapPool 是一個(gè)接口,實(shí)現(xiàn)類為 LruBitmapPool ,,具體的邏輯在 LruPoolStrategy 中,。

LruPoolStrategy 也是一個(gè)接口,它的實(shí)現(xiàn)類為 SizeConfigStrategy,,從 LruPoolStrategy 的名字可以看得出來,,BitmapPool 用的是 LruCache 來保存 Bitmap 的。

在 LruPoolStrategy 中,,會(huì)根據(jù) Bitmap 的大小和編碼選項(xiàng),,把 Bitmap 放到 GroupedLinkedHamp 中。

3.5 ArrayPool

和 BitmapPool 一樣,,ArrayPool 用的也是 LruCache,,也是為了減少不必要的內(nèi)存浪費(fèi)。

比如在輸入流編碼器 StreamEncoder 中,,當(dāng)把輸入流轉(zhuǎn)化為文件時(shí),,需要?jiǎng)?chuàng)建一個(gè)新的字節(jié)數(shù)組,如果不用 ArrayPool,,而圖片是在列表中加載的,,那就會(huì)創(chuàng)建很多不必要的的字節(jié)數(shù)組。

3.6 Glide 緩存相關(guān)問題

  1. LruCache 的緩存實(shí)現(xiàn)比較特別的是哪兩點(diǎn)?
  2. DiskLruCache 有哪 3 個(gè)特點(diǎn),?
  3. DiskCacheStrategy 定義了幾種磁盤緩存策略,?

4. Glide 初始化流程與配置

4.1 Glide 初始化流程

在看 Glide 的配置前,我們先來看下 Glide 的初始化流程,,因?yàn)樽x取配置就是在初始化的過程中讀取的,。

4.1.1 with()

當(dāng)我們調(diào)用 Glide.with() 方法時(shí),Glide 會(huì)先用 getRetriever() 方法獲取請(qǐng)求管理器檢索器,,在這個(gè)方法中還會(huì)用 get() 方法獲取 Glide 實(shí)例,,獲取不到的話就會(huì)初始化 Glide 。

4.1.2 initializeGlide()

我們可以在 AndroidManifest 中聲明 GlideModule,,也可以用 @GlideModule 注解聲明 GlideModule,,走的都是上面這個(gè)流程。

1. 應(yīng)用選項(xiàng)

Glide 有一個(gè) ApppModuleGenerator,,它會(huì)把讀取我們?cè)O(shè)定的 AppGlideModule 中的配置,,然后生成一個(gè) GeneratedAppGlideModuleImpl 配置。

然后用反射讀取這個(gè)配置,,讀取到配置后,,就會(huì)應(yīng)用我們?cè)?applyOptions() 中給 GlideBuilder 設(shè)置的選項(xiàng)。

如果不用生成加反射的話讀取配置的話,,Glide 并不知道我們會(huì)把配置叫什么,,放哪里。

2. 創(chuàng)建實(shí)例

應(yīng)用選項(xiàng)后,,就會(huì)創(chuàng)建一個(gè) Glide 實(shí)例,。

3. 注冊(cè)組件

創(chuàng)建完實(shí)例后,就會(huì)把實(shí)例的 registry 傳到 registerComponents() 中,,也就是我們修改編解碼邏輯的地方,。

4. 注冊(cè)回調(diào)

Glide 實(shí)現(xiàn)了 ComponentCallback 用于監(jiān)聽內(nèi)存狀態(tài),這里的注冊(cè)回調(diào)就是調(diào)用 ApplicationContext 的 registerComponentCallbacks() 方法,。

4.2 Registry

Glide 有一個(gè)登記處 Registry ,,它包含了下面這些 Registry 。

  • 數(shù)據(jù)加載器登記處 ModelLoaderRegistry
  • 編碼器登記處 EncoderRegistry
  • 資源解碼器登記處 ResourceDecoderRegistry
  • 資源編碼器登記處 ResourceEncoderRegistry
  • 數(shù)據(jù)重繞器登記處 DataRewinderRegistry
  • 轉(zhuǎn)碼器登記處 DataRewinderRegistry
  • 圖片頭部信息解析器登記處 ImageHeaderRegistry

在 Glide 的構(gòu)造方法中,,會(huì)把所有的編碼,、解碼和數(shù)據(jù)加載等邏輯通過 Registry 的 append() 方法登記到 Registry 中,我們可以在 AppGlideModule 的 registerComponents() 方法中獲取到 registry 實(shí)例,,通過這個(gè)實(shí)例就可以替換掉對(duì)應(yīng)的實(shí)現(xiàn),。

1. registerComponents()

比如獲取網(wǎng)絡(luò)圖片默認(rèn)用的是 HttpUrlFetcher ,HttpUrlFetcher 是用的 HttpURLConnection 來獲取圖片數(shù)據(jù)的,,我們可以在 registerComponents() 方法中,,把 HttpUrlFetcher 替換為 OkHttp ,。

2. Entry

之所以要用 Class 來替換 ModelLoader ,是因?yàn)?ModelLoaderRegistry 的 append() 方法會(huì)用來源類型(Model),、原始數(shù)據(jù)類型(Data)和 ModelLoaderFactory 來創(chuàng)建不同類型的 Entry ,,這些 Entry 會(huì)保存在 MultiModelLoaderFactory 工廠中。

當(dāng) DataFetcherGenerator 通過 ModelLoader 獲取數(shù)據(jù)時(shí),,則會(huì)通過 model 的 Class 信息來獲取 ModelLoader,,除了 ModelLoaderRegistry,其他的 Registry 中也有 Entry,。

4.3 GlideBuilder

GlideBuilder 就是 Glide 的構(gòu)建器,,它包含了下面這些數(shù)據(jù)。

  • 線程池
    • 圖片來源線程池 sourceExecutor
    • 磁盤緩存線程池 diskCacheExecutor
    • 動(dòng)畫線程池 animationExecutor
  • 內(nèi)存大小計(jì)算器 memorySizeCalculator
  • 網(wǎng)絡(luò)狀態(tài)監(jiān)聽器工廠 connectivityMonitorFactory
  • 請(qǐng)求選項(xiàng)工廠 defaultRequestOptionsFactory
  • 請(qǐng)求管理器工廠 requestManagerFactory
  • 請(qǐng)求監(jiān)聽器列表 defaultRequestListeners
  • 位圖池 bitmapPool
  • 數(shù)組池 arrayPool
  • 內(nèi)存緩存 MemoryCache
  • 磁盤緩存工廠 diskCacheFactory
  • 引擎 Engine

上面這些字段大多數(shù)都是可以在 AppGlideModule 的 applyOptions() 方法中,,調(diào)用 GlideBuilder 的 setXXX() 方法來替換實(shí)現(xiàn)的,,下面我們主要看下 Glide 線程池和內(nèi)存大小計(jì)算器。

4.3.1 Glide 線程池

GlideExecutor 是 Glide 的線程池實(shí)現(xiàn),,Glide 中有下面 4 種線程池,。

1. SourceExecutor

對(duì)圖片來源解碼的任務(wù)的線程池,線程數(shù)為最多為 4 ,,最小為設(shè)備的 CPU 核數(shù),。

2. unlimitedSourceExecutor

如果我們?cè)诩虞d圖片時(shí)調(diào)用了 useUnlimitedSourceGeneratorsPool() 選項(xiàng),那 Glide 就會(huì)用這個(gè)無線程數(shù)限制的線程池來獲取圖片,。

3. DiskCacheExecutor

對(duì)磁盤緩存數(shù)據(jù)解碼的任務(wù)的線程池,,線程數(shù)為 1 ,。

4. AnimationExecutor

這也是用來從圖片來源獲取數(shù)據(jù)的線程池,,而不是用來播放 GIF 動(dòng)畫的線程池,當(dāng)我們加載圖片時(shí)調(diào)用了 useAnimationPool(true) ,,那在獲取圖片數(shù)據(jù)時(shí) EngineJob 就會(huì)把 DecodeJob 放到 AnimationExecutor 中,。

如果設(shè)備 CPU 核數(shù)大于等于 4 ,那 AnimationPool 線程數(shù)就是 2 ,,否則就是 1 ,。

5. 自定義線程池

Glide 對(duì)于線程池只允許用 GlideBuilder 中的 Builder 來設(shè)置參數(shù),GlideExecutor.Builder 支持下面幾個(gè)參數(shù),。

  • setThreadTimeoutMillis()

    設(shè)置線程存活時(shí)間,;

  • setThreadCount()

    設(shè)置線程數(shù);

  • setUncaughtThrowableStrategy()

    設(shè)置異常處理策略,,有三種可以選,,也可以自己自定義,默認(rèn)為 LOG,。

    • IGNORE

      忽略異常,;

    • LOG

      打印異常日志,;

    • THROW

      拋出異常;

  • setName()

    設(shè)置線程名稱,;

4.3.2 內(nèi)存大小計(jì)算器

MemorySizeCalculator 負(fù)責(zé)計(jì)算 BitmapPool ,、ArrayPool 和 MemoryCache 的大小。

1. BitmapPool 大小

BitmapPool 大小為一屏可容納的最高圖片質(zhì)量的大小,,比如 1080 * 1920 * 4 ≈ 7.9M ,。

2. ArrayPool 大小

默認(rèn)為 4M,如果系統(tǒng)版本低于 19 則為 2M,。

3. 內(nèi)存緩存大小

內(nèi)存緩存大小為兩屏可容納的最高圖片質(zhì)量的大小,,比如 1080 * 1920 * 2 * 4 ≈ 15.8M 。

4. maxSizeMultiplier

MemorySizeCalculator 在計(jì)算 BitmapPool 和 MemoryCache 大小時(shí),,會(huì)通過 getMaxSize() 方法,,用 ActivityManager 獲取 memoryClasss,然后用 memoryClass 的值乘以 maxSizeMultiplier,,maxSizeMultiplier 默認(rèn)為 0.4,。

memoryClass 就是獲取應(yīng)用可用內(nèi)存大小,比如我的 VIVO 手機(jī)給應(yīng)用分配的可用內(nèi)存為 256M,,以我的手機(jī)為例,,256 * 0.4 = 102.4 ,也就是默認(rèn)情況下,, BitmapPool ,、ArrayPool 和 MemoryCache 的大小最多不會(huì)超過 102.4M。

當(dāng) BitmapPool ,、ArrayPool 和 MemoryCache 的大小加起來大于最大值時(shí),,會(huì)按這個(gè)最大值重新計(jì)算 BitmapPool 和 MemoryCache 的大小。

5. 自定義內(nèi)存大小計(jì)算方式

和 GlideExecutor 一樣,,MemorySizeCalculator 也有一個(gè) Builder,,支持下面這些參數(shù)的設(shè)置。

  • setMemoryCacheSizeScreens(screens)

    設(shè)置內(nèi)存緩存大小為幾屏的大??;

  • setBitmapPoolScreens(screens)

    設(shè)置 BitmapPool 大小為幾屏的大小,;

  • setArrayPoolSize(sizeBytes)

    設(shè)置 ArrayPool 大?。?/p>

  • setMaxSizeMultiplier()

    設(shè)置最大值乘數(shù)大??;

4.4 初始化流程與配置相關(guān)問題

  1. 什么是 Registry ?
  2. 在哪里可以替換 Glide 的數(shù)據(jù)加載邏輯,?
  3. 在哪里可以修改 Glide 的內(nèi)存使用計(jì)算方式,?
  4. Glide 有幾種線程池,?
  5. BitmapPool 和 MemoryCache 的大小是怎么計(jì)算的?

5. Glide 圖片加載選項(xiàng)

1. placeholder(drawable)

如果用戶打開 App 的時(shí)候,,本來應(yīng)該顯示圖片的控件,,由于網(wǎng)絡(luò)原因等了好幾秒都沒加載出來,這樣用戶體驗(yàn)就不好,,所以我們可以加上一張占位圖,,這樣用戶就知道圖片等下就出來了。

這里要注意的是,,占位圖只能是 App 內(nèi)置圖片,,不能是網(wǎng)絡(luò)圖片,否則無網(wǎng)絡(luò)的時(shí)候它就沒作用了,。

2. error(drawable)

當(dāng)用戶的網(wǎng)絡(luò)出現(xiàn)錯(cuò)誤,,圖片加載失敗時(shí),一直顯示占位圖,,用戶就會(huì)一直等待,,如果等了半天都沒加載出來,用戶就會(huì)覺得我們的 App 有問題,。

這時(shí)候我們可以用一張錯(cuò)誤占位圖,,這樣用戶就知道有可能是網(wǎng)絡(luò)出問題了,切換一下網(wǎng)絡(luò),,又或者是主動(dòng)聯(lián)系開發(fā)者,。

如果沒有設(shè)置這個(gè)參數(shù)的話,出錯(cuò)時(shí)會(huì)顯示 placeholder 中傳的占位圖,。

3. fallback()

設(shè)置當(dāng)數(shù)據(jù)模型為空,,也就是我們傳入 load() 中的值為空時(shí)要顯示的圖片,沒有設(shè)置 fallback 會(huì)顯示錯(cuò)誤占位圖,,連錯(cuò)誤占位圖也沒設(shè)置就會(huì)顯示 placeholder 占位圖,。

4. override(width, height)

如果我們不想讓 Glide 把圖片按 ImageView 的大小進(jìn)行縮放,,我們可以用這個(gè)方法來設(shè)置加載的目標(biāo)寬高,。

5. fitCenter()

fitCenter 是一個(gè)圖片裁剪選項(xiàng),用于把圖片尺寸限定在 ImageView 內(nèi)并居中,,這樣圖片就能完全顯示,。

選擇這個(gè)選項(xiàng)后,當(dāng)圖片的寬高比和 ImageView 的寬高比不同時(shí),,ImageView 就不會(huì)被填滿,。

6. centerCrop()

當(dāng)我們使用了 centerCrop (),并且圖片寬高比與 ImageView 不同時(shí),,Glide 會(huì)裁剪中間的部分,,以填滿 ImageView ,,這時(shí)圖像就不是完全顯示的了。

7. centerInside()

與 fitCenter 類似,,不同的是,,當(dāng) ImageView 的尺寸為 wrap_content 時(shí),fitCenter() 會(huì)把圖片放大,,而 centerInside() 則會(huì)保持原圖大小,。

8. transform(Transformation)

設(shè)置變換選項(xiàng),比如旋轉(zhuǎn)選項(xiàng) Rotate 和圓角選項(xiàng) RoundedCorners 沒有對(duì)應(yīng)的方法可以直接設(shè)置,,就可以用這個(gè)方法傳進(jìn)去,。

如果想要同時(shí)多種變換選項(xiàng),也要從這個(gè)參數(shù)傳進(jìn)去,,比如 transform(CenterCrop(), RoundedCorners()) ,,這樣創(chuàng)建的就是多重變換 MultiTransformation ,否則只有后面設(shè)置的變換選項(xiàng)會(huì)起效,。

9. dontTransform()

禁止變換,,調(diào)用這個(gè)方法后會(huì)刪除之前設(shè)定的變換選項(xiàng)。

10. skipMemoryCache(boolean)

跳過內(nèi)存緩存,。

默認(rèn)情況下 Glide 會(huì)把圖片放在內(nèi)存緩存中,,如果我們不想要讓某張圖片保留在內(nèi)存緩存中,比如加載高清原圖時(shí),,可以把這個(gè)值改為 true ,。

11. diskCacheStrategy(strategy)

磁盤緩存策略,Glide 自帶了 5 種磁盤緩存策略,,默認(rèn)為 AUTOMATIC,。

  • ALL
  • NONE
  • DATA
  • RESOURCE
  • AUTOMATIC
12. onlyRetrieveFromCache(boolean)

如果傳 true ,表示不從圖片來源獲取數(shù)據(jù),,只從緩存中讀取數(shù)據(jù),。

13.priority

設(shè)置加載圖片的優(yōu)先級(jí),比如運(yùn)營圖的優(yōu)先級(jí)就比其他圖片高,,Glide 的加載優(yōu)先級(jí)有下面四種,。

  • IMMEDIATE

    立即加載;

  • HIGH

    高優(yōu)先級(jí),;

  • NORMAL

    正常優(yōu)先級(jí),;

  • LOW

    低優(yōu)先級(jí);

14. sizeMultiplier(float)

按比例縮放圖片,。

15. encodeFormat(CompressFormat)

設(shè)置下載或緩存的圖片的編碼類型,,比如 JPEG、PNG,、WEBP,。

如果沒有設(shè)置 encodeFormat,,并且圖像有透明通道,那 Glide 默認(rèn)會(huì)把以 PNG 的方式保存圖片,,否則就是 JPEG,。

16. encodeQuality(int)

設(shè)置下載或緩存的圖片的編碼質(zhì)量,這個(gè)參數(shù)會(huì)傳到 Bitmap.compress() 方法中,。

17. frame(long)

取視頻中某一幀的作為圖片,。

18. format(DecodeFormat)

設(shè)置解碼格式,比如 ARGB_8888,、RGB_565 ,。

19. timeout(milliseconds)

設(shè)置網(wǎng)絡(luò)圖片的請(qǐng)求超時(shí),默認(rèn)為 2500 毫秒,。

20. transition(options)

設(shè)置過渡動(dòng)畫,,這里的 options 傳的是 TransitionOptions ,這是一個(gè)抽象類,,它有三個(gè)子類,。

  • GenericTransitionOptions.with()

    自定義動(dòng)畫。

  • DrawableTransitionOptions.withCrossFade()

    設(shè)置圖片淡入動(dòng)畫,。

  • BitmapTransitionOptions.withCrossFade()

    如果調(diào)用了 asBitmap() 方法,,就要用這個(gè)過渡動(dòng)畫。

21. dontAnimate()

不播放 GIF 動(dòng)畫 ,。

22. apply(options)

應(yīng)用選項(xiàng),。

23. listener(RequestListener)

設(shè)置請(qǐng)求監(jiān)聽器 ,這個(gè)接口有下面兩個(gè)回調(diào),。

  • onResourceReady()

    圖片加載完成回調(diào),。

  • onLoadFailed()

    圖片加載失敗回調(diào)。

24. asBitmap()

把解碼類型改為 Bitmap ,。

這個(gè)方法并不是 BaseRequestOptions 提供的,,而是 RequestManager 中的,但是對(duì)于外部使用者來說,,這就是一個(gè)加載選項(xiàng),,不同的是,這個(gè)選項(xiàng)需要在 load() 方法前調(diào)用,。

25.asFile()

把解碼類型改為 File,,也就是用 submit().get() 獲取到的類型為 File 。

26. submit()

我們可以用 submit() 方法來獲取我們想要的圖片類型,,比如文件、Bitmap 和 Drawable 等,,但是要注意的是這個(gè)方法要在子線程中執(zhí)行,。

27. downloadOnly()

設(shè)定只下載圖片,,不加載圖片。

這個(gè)選項(xiàng)就是 asFile() + diskCacheStrategy(DATA) + priority(LOW) + skiptMmoeryCache(true) ,。

28. download()

這個(gè)方法相當(dāng)于是用 download(image) 替換 downloadOnly().load(image) ,。

29. preload(width, height)

預(yù)加載圖片,可以用來提前下載一些下一次啟動(dòng)應(yīng)用的時(shí)候會(huì)用到的圖片,,比如閃屏頁廣告,。

和 downloadOnly() 的區(qū)別在于不需要在子線程調(diào)用。

參考資料

  • 10大開源框架源碼解析
  • Glide最新版V4使用指南
  • Android圖片加載框架最全解析(八),,帶你全面了解Glide 4的用法
  • HashMap的key是對(duì)象

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多