[TOC]
# Glide做了哪些優化?
要想要回答這個問題,我們可以先想一想,如果我們自己要實現一個圖片加載框架,我們會思考什么問題?
1.圖片下載是個耗時過程,我們首先需要考慮的就是圖片緩存的問題
2.圖片加載也是個耗內存的操作,很多`OOM`都是圖片加載導致的,所以我們也要考慮內存優化問題
3.圖片加載到一半,頁面關閉了,圖片加載也應該中止,這又牽扯到了生命周期管理的問題
4.還有就是圖片加載框架是否支持大圖加載?大圖情況下會有什么問題?
以上就是我們提出的有關于`Glide`的幾個問題了,這樣我們可以輕松得出本文主要包括的內容
1.`Glide`圖片加載的總體流程介紹
2.`Glide`緩存機制做了哪些優化?
3.`Glide`做了哪些內存優化?
4.`Glide`如何管理生命周期?
5.`Glide`怎么做大圖加載?
下面就帶著問題進入正文~
## `Glide`圖片加載總體流程介紹
在開始了解`Glide`具體做了哪些優化之前,我們先對`Glide`圖片加載的總體流程做一個簡單的介紹,讓大家首先有個整體概念。
同時在后面對`Glide`做的優化具體發生在哪一步也可以方便的知道.
概括來說,圖片加載包含封裝,解析,下載,解碼,變換,緩存,顯示等操作,如下圖所示:

* 1.封裝參數:從指定來源,到輸出結果,中間可能經歷很多流程,所以第一件事就是封裝參數,這些參數會貫穿整個過程;
* 2.解析路徑:圖片的來源有多種,格式也不盡相同,需要規范化;
* 3.讀取緩存:為了減少計算,通常都會做緩存;同樣的請求,從緩存中取圖片(`Bitmap`)即可;
* 4.查找文件/下載文件:如果是本地的文件,直接解碼即可;如果是網絡圖片,需要先下載;
* 5.解碼:這一步是整個過程中最復雜的步驟之一,有不少細節;
* 6.變換:解碼出`Bitmap`之后,可能還需要做一些變換處理(圓角,濾鏡等);
* 7.緩存:得到最終bitmap之后,可以緩存起來,以便下次請求時直接取結果;
* 8.顯示:顯示結果,可能需要做些動畫(淡入動畫,crossFade等)。
以上就是`Glide`圖片加載的總體流程,這里只做了簡單的介紹,詳情可見:[聊一聊關于Glide在面試中的那些事](https://juejin.cn/post/6844904002551808013 "https://juejin.cn/post/6844904002551808013")
## `Glide`緩存機制做了哪些優化?
我們知道,下載圖片是非常耗費資源的,所以圖片緩存機制是圖片加載框架很重要的一部分,下面就以一張表格來說明下 Glide 緩存。
| 緩存類型 | 緩存代表 | 說明 |
| --- | --- | --- |
| 活動緩存 | ActiveResources | 如果當前對應的圖片資源是從內存緩存中獲取的,那么會將這個圖片存儲到活動資源中。 |
| 內存緩存 | LruResourceCache | 圖片解析完成并最近被加載過,則放入內存中 |
| 磁盤緩存-資源類型 | DiskLruCacheWrapper | 被解碼后的圖片寫入磁盤文件中 |
| 磁盤緩存-原始數據 | DiskLruCacheWrapper | 網絡請求成功后將原始數據在磁盤中緩存 |
在介紹具體緩存前,先來看一張加載緩存執行順序,有個大概的印象

`Glide`的緩存機制,主要分為2種緩存,一種是內存緩存,一種是磁盤緩存。
之所以使用內存緩存的原因是:防止應用重復將圖片讀入到內存,造成內存資源浪費。
之所以使用磁盤緩存的原因是:防止應用重復的從網絡或者其他地方下載和讀取數據。
正式因為有著這兩種緩存的結合,才構成了`Glide`極佳的緩存效果。
### 內存緩存
`Glide`默認開啟內存緩存,我們也可以通過`skipMemoryCache`關閉
上面我們可以看到內存緩存其實分兩個部分,`ActiveResource`緩存與`LRU`緩存
`ActiveResources` 就是一個弱引用的 `HashMap` ,用來緩存正在使用中的圖片,使用 `ActiveResources` 來緩存正在使用中的圖片,可以保護這些圖片不會被 `LruCache` 算法回收掉
內存緩存加載順序如下:
1.根據圖片地址,寬高,變換,簽名等生成`key`
2.第一次加載沒有獲取到活動緩存。
3.接著加載內存資源緩存,先清理掉內存緩存,在添加進行活動緩存。
4.第二次加載活動緩存已經存在。
5.當前圖片引用為 0 的時候,清理活動資源,并且添加進內存資源。
6.又回到了第一步,然后就這樣環環相扣。
總結為流程圖如下:

這里沒有貼出源碼,如果想要看源碼的同學可參考:[從源碼的角度分析 Glide 緩存策略](https://juejin.cn/post/6844903953604280328#heading-3 "https://juejin.cn/post/6844903953604280328#heading-3")
我們上面總結了`Glide`內存緩存加載的流程,看到這里我們很容易有個疑問,為什么`Glide`要設計兩種內存緩存?
#### 為什么設計兩種內存緩存?
> `LruCache`算法的實現,你會發現它其實是用一個`LinkedHashMap`來緩存對象的,每次內存超出緩存設定的時候,就會把最近最少使用的緩存去掉,因此有可能會把正在使用的緩存給誤傷了,我還在用著它呢就給移出去了。因此這個弱引用可能是對正在使用中的圖片的一種保護,使用的時候先從`LruCache`里面移出去,用完了再把它重新加到緩存里面。
舉個例子

比如我們 `Lru` 內存緩存 `size` 設置裝 99 張圖片,在滑動 `RecycleView` 的時候,如果剛剛滑動到 100 張,那么就會回收掉我們已經加載出來的第一張,這個時候如果返回滑動到第一張,會重新判斷是否有內存緩存,如果沒有就會重新開一個 `Request` 請求,很明顯這里如果清理掉了第一張圖片并不是我們要的效果。所以在從內存緩存中拿到資源數據的時候就主動添加到活動資源中,并且清理掉內存緩存中的資源。這么做很顯然好處是 保護不想被回收掉的圖片不被 `LruCache` 算法回收掉,充分利用了資源。
#### 小結
本節主要總結了`Glide`內存緩存加載的流程
1.首先去獲取活動緩存,如果加載到則直接返回,沒有則進入下一步
2.接著去獲取`LRU`緩存,在獲取時會將其從`LRU`中刪除并添加到活動緩存中
3.下次加載就可以直接加載活動緩存了
4.當圖片引用為0時,會從活動緩存中清除并添加到`LRU`緩存中
5.之所以要設計兩種內存緩存的原因是為了防止加載中的圖片被`LRU`回收
### 磁盤緩存
首先了解一下磁盤緩存策略
* `DiskCacheStrategy.NONE`: 表示不緩存任何內容。
* `DiskCacheStrategy.RESOURCE`: 在資源解碼后將數據寫入磁盤緩存,即經過縮放等轉換后的圖片資源。
* `DiskCacheStrategy.DATA`: 在資源解碼前將原始數據寫入磁盤緩存。
* `DiskCacheStrategy.ALL` : 使用`DATA`和`RESOURCE`緩存遠程數據,僅使用`RESOURCE`來緩存本地數據。
* `DiskCacheStrategy.AUTOMATIC`:它會嘗試對本地和遠程圖片使用最佳的策略。當你加載遠程數據時,`AUTOMATIC` 策略僅會存儲未被你的加載過程修改過的原始數據,因為下載遠程數據相比調整磁盤上已經存在的數據要昂貴得多。對于本地數據,`AUTOMATIC` 策略則會僅存儲變換過的縮略圖,因為即使你需要再次生成另一個尺寸或類型的圖片,取回原始數據也很容易。默認使用這種緩存策略
在了解磁盤緩存時我們主要需要明確一個概念,是當我們使用 `Glide` 去加載一張圖片的時候,`Glide` 默認并不會將原始圖片展示出來,而是會對圖片進行壓縮和轉換,總之就是經過種種一系列操作之后得到的圖片,就叫轉換過后的圖片。
我們既可以緩存變換之前的原始圖片,也可以緩存變換后的圖片
### 為什么需要兩種磁盤緩存
上文已經說了,`DiskCacheStrategy.RESOURCE`緩存的是變換后的資源,`DiskCacheStrategy.DATA`緩存的是變換前的資源
舉個例子,同一張圖片,我們先在`100*100`的`View`是展示,再在`200*200`的`View`上展示
如果不緩存變換后的類型相當于每次都要進行一次變換操作,如果不緩存原始數據則每次都要去重新下載數據
如下可以看出,兩種緩存的`key`不一樣
~~~java
DiskCacheStrategy.RESOURCE
currentKey = new ResourceCacheKey(helper.getArrayPool(),sourceId,helper.getSignature(),helper.getWidth(),helper.getHeight(),transformation,resourceClass,helper.getOptions());
DiskCacheStrategy.DATA
DataCacheKey newOriginalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
~~~
### 小結
本節主要介紹了`Glide`磁盤緩存的幾種策略并介紹了為什么需要兩種磁盤緩存的原因
這里也沒有貼什么源碼,如果想要看源碼的同學可參考:[從源碼的角度分析 Glide 緩存策略](https://juejin.cn/post/6844903953604280328#heading-8 "https://juejin.cn/post/6844903953604280328#heading-8")
## `Glide`做了哪些內存優化?
`Glide`的內存優化主要也是對`Bitmap`的優化,在回答這個問題前,我們可以想想有哪些常見的`Bitmap`優化手段
1.當圖片大小與`View`大小不一致時,可以用`inSampleSize`進行尺寸優化
2.圖片所占內存即寬*高*每像素所占內存大小,不同的模式每個像素所占的內存大小不同,我們可以利用`inpreferredconfig`配置
3.`Bitmpa`所占內存比較大,如果頻繁創建回收`Bitmap`內存可能造成內存抖動,我們可以利用`inBitmap`利用`Bitmap`內存
4.內存緩存,上文我們已經介紹了`Glide`的弱引用緩存與`LRU`緩存
其實常見的`Bitmap`內存優化也就這么幾種了,不過我們在工作中比較少直接使用他們。
下面我們就介紹下`Glide`中具體是怎么使用他們的.
### 尺寸優化
當裝載圖片的容器例如ImageView只有`100*100`,而圖片的分辨率為`800 * 800`,這個時候將圖片直接放置在容器上,很容易`OOM`,同時也是對圖片和內存資源的一種浪費。當容器的寬高都很小于圖片的寬高,其實就需要對圖片進行尺寸上的壓縮,將圖片的分辨率調整為`ImageView`寬高的大小,一方面不會對圖片的質量有影響,同時也可以很大程度上減少內存的占用
我們通常使用`inSampleSize`對`Bitmap`進行尺寸縮放
> 如果`inSampleSize` 設置的值大于1,則請求解碼器對原始的`bitmap`進行子采樣圖像,然后返回較小的圖片來減少內存的占用,例如`inSampleSize` == 4,則采樣后的圖像寬高為原圖像的1/4,而像素值為原圖的1/16,也就是說采樣后的圖像所占內存也為原圖所占內存的1/16;當`inSampleSize` <=1時,就當作1來處理也就是和原圖一樣大小。另外最后一句還注明,`inSampleSize`的值一直為2的冪,如1,2,4,8。任何其他的值也都是四舍五入到最接近2的冪。
~~~java
//1
int widthScaleFactor = orientedSourceWidth / outWidth;
int heightScaleFactor = orientedSourceHeight / outHeight;
//2
int scaleFactor =
rounding == SampleSizeRounding.MEMORY
? Math.max(widthScaleFactor, heightScaleFactor)
: Math.min(widthScaleFactor, heightScaleFactor);
int powerOfTwoSampleSize;
//3
if (Build.VERSION.SDK_INT <= 23
&& NO_DOWNSAMPLE_PRE_N_MIME_TYPES.contains(options.outMimeType)) {
powerOfTwoSampleSize = 1;
} else {
//4
powerOfTwoSampleSize = Math.max(1, Integer.highestOneBit(scaleFactor));
//5
if (rounding == SampleSizeRounding.MEMORY
// exactScaleFactor由各個裁剪策略如CenterCrop重寫得到,詳情可見代碼
&& powerOfTwoSampleSize < (1.f / exactScaleFactor)) {
powerOfTwoSampleSize = powerOfTwoSampleSize << 1;
}
}
options.inSampleSize = powerOfTwoSampleSize;
~~~
如上就是`Glide`圖片進行尺寸縮放相關的代碼
1.首先計算出圖片與`View`的寬高比
2.根據縮放策略是省內存還是高品質,決定取寬高比的最大值還是最小值
3.當`Build.VERSION.SDK_INT<=23`時,一些格式的圖片不能縮放
4.`highestOneBit`的功能是把我們計算的比例四舍五入到最接近2的冪
5.如果縮放策略為省內存,并且我們計算的`SampleSize<exactScaleFactor`,將`inSampleSize*2`
如上就是`Glide`圖片加載時做尺寸優化的大概邏輯
### 圖片格式優化
我們知道,`Bitmap`所占內存大小,由`寬*高*每像素所占內存`決定
上面的尺寸優化決定寬高,圖片格式優化決定每像素所占內存
在`API29`中,將`Bitmap`分為`ALPHA_8`, `RGB_565`, `ARGB_4444`, `ARGB_8888`, `RGBA_F16`, `HARDWARE`六個等級。
* `ALPHA_8`:不存儲顏色信息,每個像素占1個字節;
* `RGB_565`:僅存儲`RGB`通道,每個像素占2個字節,對`Bitmap`色彩沒有高要求,可以使用該模式;
* `ARGB_4444`:已棄用,用`ARGB_8888`代替;
* `ARGB_8888`:每個像素占用4個字節,保持高質量的色彩保真度,默認使用該模式;
* `RGBA_F16`:每個像素占用8個字節,適合寬色域和`HDR`;
* `HARDWARE`:一種特殊的配置,減少了內存占用同時也加快了`Bitmap`的繪制。
每個等級每個像素所占用的字節也都不一樣,所存儲的色彩信息也不同。同一張100像素的圖片,`ARGB_8888`就占了400字節,`RGB_565`才占200字節,RGB\_565在內存上取得了優勢,但是`Bitmap`的色彩值以及清晰度卻不如`ARGB_8888`模式下的`Bitmap`
值得注意的是在`Glide4.0`之前,`Glide`默認使用`RGB565`格式,比較省內存
但是`Glide4.0`之后,默認格式已經變成了`ARGB_8888`格式了,這一優勢也就不存在了。
這本身也就是質量與內存之間的取舍,如果應用所需圖片的質量要求不高,也可以修改默認格式
~~~java
//默認格式修改為了ARGB_8888
public static final Option<DecodeFormat> DECODE_FORMAT =
Option.memory(
"com.bumptech.glide.load.resource.bitmap.Downsampler.DecodeFormat", DecodeFormat.DEFAULT);
~~~
### 內存復用優化
`Bitmap`所占內存比較大,如果我們頻繁創建與回收`Bitmap`,那么很容易造成內存抖動,所以我們應該盡量復用`Bitmap`內存
`Glide`主要使用了`inBitmap`與`BitmapPool`來實現內存的復用
#### `inBitmap`介紹
在 `Android 3.0(API 級別 11)`開始,系統引入了 `BitmapFactory.Options.inBitmap` 字段。如果設置了此選項,那么采用 `Options` 對象的解碼方法會在生成目標 `Bitmap` 時嘗試復用 `inBitmap`,這意味著 `inBitmap` 的內存得到了重復使用,從而提高了性能,同時移除了內存分配和取消分配。不過 `inBitmap` 的使用方式存在某些限制,在 `Android 4.4(API 級別 19)`之前系統僅支持復用大小相同的位圖,4.4 之后只要 `inBitmap` 的大小比目標 `Bitmap` 大即可
#### `BitmapPool`介紹
通過上文我們知道了可以通過`inBitmap`復用內存,但是還需要一個地方存儲可復用的`Bitmap`,這就是`BitmapPool`
`JDK` 中的 `ThreadPoolExecutor` 相信大多數開發者都很熟悉,我們一般將之稱為“線程池”。池化是一個很常見的概念,其目的都是為了實現對象復用,例如 `ThreadPoolExecutor` 就實現了線程的復用機制
`BitmapPool`即實現了`Bitmap`的池化
#### `Glide`的應用
~~~java
private static void setInBitmap(
BitmapFactory.Options options, BitmapPool bitmapPool, int width, int height) {
@Nullable Bitmap.Config expectedConfig = null;
if (expectedConfig == null) {
expectedConfig = options.inPreferredConfig;
}
// BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
options.inBitmap = bitmapPool.getDirty(width, height, expectedConfig);
}
~~~
如上即是`Glide`設置`inBitmap`的代碼,向`BitmapPool`中傳入寬高與格式,得到一個可復用的對象,這樣就實現了`Bitmap`的內存復用
由于篇幅原因,詳細的源碼這里沒有貼出來,想要了解更多的讀者可參考:[Coil 和 Glide 的 Bitmap 緩存復用機制](https://juejin.cn/post/6956090846470995975 "https://juejin.cn/post/6956090846470995975")
## `Glide`如何管理生命周期?
當我們在做一個網絡請示時,頁面退出時應該中止請示,不然容易造成內存泄漏
對于圖片加載也是如此,我們在頁面退出時應該中止請示,銷毀資源。
但是我們使用`Glide`的時候卻不需要在頁面退出時做什么操作,說明`Glide`可以做到在頁面關閉時自動釋放資源
下面我們一起看下`Glide`是如何實現的
主要是兩步:
1.調用時通過`Glide.with`傳入`context`,利用`context`構建一個`Fragment`
2.監聽`Fragment`生命周期,銷毀時釋放`Glide`資源
### 傳入`context`構建`Fragment`
~~~java
//通過Activity拿到RequestManager
public RequestManager get(@NonNull Activity activity) {
//拿到當前Activity的FragmentManager
android.app.FragmentManager fm = activity.getFragmentManager();
//生成一個Fragment去綁定一個請求管理RequestManager
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//①在當前Activity添加一個Fragment用于管理請求的生命周期
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
//獲取RequestManager
RequestManager requestManager = current.getRequestManager();
//如果不存在RequestManager,則創建
if (requestManager == null) {
Glide glide = Glide.get(context);
//②構建RequestManager
//current.getGlideLifecycle()就是ActivityFragmentLifecycle,也就是構建RequestManager時會傳入fragment中的ActivityFragmentLifecycle
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//將構建出來的RequestManager綁定到fragment中
current.setRequestManager(requestManager);
}
//返回當前請求的管理者
return requestManager;
}
復制代碼
~~~
如上所示:
1.在當前`Activity`添加一個透明`Fragment`用于管理請示生命周期
2.構建`RequestManager`并傳入`Fragment`生命周期
### `RequestManager`監聽生命周期
~~~java
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
...
//將當前對象注冊到ActivityFragmentLifecycle
lifecycle.addListener(this);
}
//...
//RequestManager實現了fragment生命周期回調
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}
@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
}
}
public class RequestManagerFragment extends Fragment {
//生命周期的關鍵就在ActivityFragmentLifecycle
private final ActivityFragmentLifecycle lifecycle;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
//...
}
復制代碼
~~~
邏輯很簡單:`Fragment`生命周期變化會回調`RequestManager`生命周期,然后在進行相關的資源釋放工作
### 小結

`Glide.with(this)`綁定了`Activity`的生命周期。在`Activity`內新建了一個無`UI`的`Fragment`,這個`Fragment`持有一個`Lifecycle`,通過`Lifecycle`在`Fragment`關鍵生命周期通知`RequestManager進`行相關從操作。在生命周期`onStart`時繼續加載,`onStop`時暫停加載,`onDestory`時停止加載任務和清除操作。
由于篇幅有限,這里沒有貼太多代碼,更多細節可參考:[Glide生命周期管理](https://link.juejin.cn?target=https%3A%2F%2Fwww.jianshu.com%2Fp%2F190285e18ae1 "https://www.jianshu.com/p/190285e18ae1")
## `Glide`怎么做大圖加載
對于圖片加載還有種情況,就是單個圖片非常巨大,并且還不允許壓縮。比如顯示:世界地圖、清明上河圖、微博長圖等
首先不壓縮,按照原圖尺寸加載,那么屏幕肯定是不夠大的,并且考慮到內存的情況,不可能一次性整圖加載到內存中
所以這種情況的優化思路一般是局部加載,通過`BitmapRegionDecoder`來實現
這種情況下通常`Glide`只負責將圖片下載下來,圖片的加載由我們自定義的`ImageView`來實現
### `BitmapRegionDecoder`介紹
`BitmapRegionDecoder`主要用于顯示圖片的某一塊矩形區域,如果你需要顯示某個圖片的指定區域,那么這個類非常合適。
對于該類的用法,非常簡單,既然是顯示圖片的某一塊區域,那么至少只需要一個方法去設置圖片;一個方法傳入顯示的區域即可
舉個例子:
~~~java
//設置顯示圖片的中心區域
BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - 100, height / 2 - 100, width / 2 + 100, height / 2 + 100), options);
mImageView.setImageBitmap(bitmap);
復制代碼
~~~
更詳細的實現可見:[Android 高清加載巨圖方案 拒絕壓縮圖片](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Flmj623565791%2Farticle%2Fdetails%2F49300989%2F "https://blog.csdn.net/lmj623565791/article/details/49300989/")
不過這種方法雖然也能加載大圖,但做的還不夠,滑動時內存抖動,卡頓現象比較明顯,不能用于線上
 下面介紹一種可以用于線上的大圖加載方案
## 可用于線上的大圖加載方案
介紹一個開源庫:[subsampling-scale-image-view](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fdavemorrissey%2Fsubsampling-scale-image-view "https://github.com/davemorrissey/subsampling-scale-image-view")
`SubsamplingScaleImageView`將大圖切片,再判斷是否可見,如果可見則加入內存中,否則回收,減少了內存占用與抖動 同時根據不同的縮放比例選擇合適的采樣率,進一步減少內存占用 同時在子線程進行decodeRegion操作,解碼成功后回調至主線程,減少UI卡頓.
之前我也做`BitmapRegionDecoder`與`SubsamplingScaleImageView`的內存分析
有興趣的同學也可以了解下:[Android性能優化之UI卡頓優化實例分析](https://juejin.cn/post/6870389004387385352 "https://juejin.cn/post/6870389004387385352")
## 總結
本文主要以`Glide`做了哪些優化為切入點,回答了如下幾個問題
1.說一下`Glide`圖片加載的總體流程
2.`Glide`緩存機制做了哪些優化?
3.`Glide`做了哪些內存優化?
4.`Glide`如何管理生命周期?
5.`Glide`怎么做大圖加載?
如果對您有所幫助,歡迎點贊,謝謝~
# 參考資料
[【帶著問題學】Glide做了哪些優化?](https://juejin.cn/post/6970683481127043085)
- Android
- 四大組件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介紹
- MessageQueue詳細
- 啟動流程
- 系統啟動流程
- 應用啟動流程
- Activity啟動流程
- View
- view繪制
- view事件傳遞
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大數據
- Binder小結
- Android組件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 遷移與修復
- Sqlite內核
- Sqlite優化v2
- sqlite索引
- sqlite之wal
- sqlite之鎖機制
- 網絡
- 基礎
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP進化圖
- HTTP小結
- 實踐
- 網絡優化
- Json
- ProtoBuffer
- 斷點續傳
- 性能
- 卡頓
- 卡頓監控
- ANR
- ANR監控
- 內存
- 內存問題與優化
- 圖片內存優化
- 線下內存監控
- 線上內存監控
- 啟動優化
- 死鎖監控
- 崩潰監控
- 包體積優化
- UI渲染優化
- UI常規優化
- I/O監控
- 電量監控
- 第三方框架
- 網絡框架
- Volley
- Okhttp
- 網絡框架n問
- OkHttp原理N問
- 設計模式
- EventBus
- Rxjava
- 圖片
- ImageWoker
- Gilde的優化
- APT
- 依賴注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 協程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 運行期Java-hook技術
- 編譯期hook
- ASM
- Transform增量編譯
- 運行期Native-hook技術
- 熱修復
- 插件化
- AAB
- Shadow
- 虛擬機
- 其他
- UI自動化
- JavaParser
- Android Line
- 編譯
- 疑難雜癥
- Android11滑動異常
- 方案
- 工業化
- 模塊化
- 隱私合規
- 動態化
- 項目管理
- 業務啟動優化
- 業務架構設計
- 性能優化case
- 性能優化-排查思路
- 性能優化-現有方案
- 登錄
- 搜索
- C++
- NDK入門
- 跨平臺
- H5
- Flutter
- Flutter 性能優化
- 數據跨平臺