<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # Glide做了哪些優化? 要想要回答這個問題,我們可以先想一想,如果我們自己要實現一個圖片加載框架,我們會思考什么問題? 1.圖片下載是個耗時過程,我們首先需要考慮的就是圖片緩存的問題 2.圖片加載也是個耗內存的操作,很多`OOM`都是圖片加載導致的,所以我們也要考慮內存優化問題 3.圖片加載到一半,頁面關閉了,圖片加載也應該中止,這又牽扯到了生命周期管理的問題 4.還有就是圖片加載框架是否支持大圖加載?大圖情況下會有什么問題? 以上就是我們提出的有關于`Glide`的幾個問題了,這樣我們可以輕松得出本文主要包括的內容 1.`Glide`圖片加載的總體流程介紹 2.`Glide`緩存機制做了哪些優化? 3.`Glide`做了哪些內存優化? 4.`Glide`如何管理生命周期? 5.`Glide`怎么做大圖加載? 下面就帶著問題進入正文~ ## `Glide`圖片加載總體流程介紹 在開始了解`Glide`具體做了哪些優化之前,我們先對`Glide`圖片加載的總體流程做一個簡單的介紹,讓大家首先有個整體概念。 同時在后面對`Glide`做的優化具體發生在哪一步也可以方便的知道. 概括來說,圖片加載包含封裝,解析,下載,解碼,變換,緩存,顯示等操作,如下圖所示: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/552652e7cc024d7297cfc15e9b0ae6dd~tplv-k3u1fbpfcp-watermark.awebp) * 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 | 網絡請求成功后將原始數據在磁盤中緩存 | 在介紹具體緩存前,先來看一張加載緩存執行順序,有個大概的印象 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/750d9bb09f2e4e8c8b0975ec43b941fa~tplv-k3u1fbpfcp-watermark.awebp) `Glide`的緩存機制,主要分為2種緩存,一種是內存緩存,一種是磁盤緩存。 之所以使用內存緩存的原因是:防止應用重復將圖片讀入到內存,造成內存資源浪費。 之所以使用磁盤緩存的原因是:防止應用重復的從網絡或者其他地方下載和讀取數據。 正式因為有著這兩種緩存的結合,才構成了`Glide`極佳的緩存效果。 ### 內存緩存 `Glide`默認開啟內存緩存,我們也可以通過`skipMemoryCache`關閉 上面我們可以看到內存緩存其實分兩個部分,`ActiveResource`緩存與`LRU`緩存 `ActiveResources` 就是一個弱引用的 `HashMap` ,用來緩存正在使用中的圖片,使用 `ActiveResources` 來緩存正在使用中的圖片,可以保護這些圖片不會被 `LruCache` 算法回收掉 內存緩存加載順序如下: 1.根據圖片地址,寬高,變換,簽名等生成`key` 2.第一次加載沒有獲取到活動緩存。 3.接著加載內存資源緩存,先清理掉內存緩存,在添加進行活動緩存。 4.第二次加載活動緩存已經存在。 5.當前圖片引用為 0 的時候,清理活動資源,并且添加進內存資源。 6.又回到了第一步,然后就這樣環環相扣。 總結為流程圖如下: ![](https://img.kancloud.cn/56/b3/56b38ce65aec414430f71596ec933ca5_960x988.png) 這里沒有貼出源碼,如果想要看源碼的同學可參考:[從源碼的角度分析 Glide 緩存策略](https://juejin.cn/post/6844903953604280328#heading-3 "https://juejin.cn/post/6844903953604280328#heading-3") 我們上面總結了`Glide`內存緩存加載的流程,看到這里我們很容易有個疑問,為什么`Glide`要設計兩種內存緩存? #### 為什么設計兩種內存緩存? > `LruCache`算法的實現,你會發現它其實是用一個`LinkedHashMap`來緩存對象的,每次內存超出緩存設定的時候,就會把最近最少使用的緩存去掉,因此有可能會把正在使用的緩存給誤傷了,我還在用著它呢就給移出去了。因此這個弱引用可能是對正在使用中的圖片的一種保護,使用的時候先從`LruCache`里面移出去,用完了再把它重新加到緩存里面。 舉個例子 ![](https://img.kancloud.cn/50/a4/50a4b00e79fa5d81a4b93b4f0d61b9fc_1105x960.png) 比如我們 `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`生命周期,然后在進行相關的資源釋放工作 ### 小結 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/926e97d193d14bb88184079b4932dc86~tplv-k3u1fbpfcp-watermark.awebp) `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/") 不過這種方法雖然也能加載大圖,但做的還不夠,滑動時內存抖動,卡頓現象比較明顯,不能用于線上 ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a433a5e33dfb47b8a60a76eebeb11e13~tplv-k3u1fbpfcp-watermark.awebp) 下面介紹一種可以用于線上的大圖加載方案 ## 可用于線上的大圖加載方案 介紹一個開源庫:[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)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看