原文地址:https://blog.mindorks.com/how-the-android-image-loading-library-glide-and-fresco-works-962bc9d1cc40
通常,我們在加載圖片的時候經常會遇到如下的問題:
- 內存溢出錯誤
- 圖片加載到視圖中比較緩慢
- UI變得無響應,并且不能平滑滾動
讓我們來看一下它們是如何一個一個解決這些問題的
內存溢出錯誤
Glide做了向下采樣的工作,向下采樣意味著將bitmap縮放到一個視圖實際需要的一個較小的尺寸。更通俗的講就是我們有一個20002000的圖片,但是我們的view大小為400400,Glide就會將我們的圖片縮小為400*400的然后顯示到View中。
Glide知道作為參數傳入的Imageview的大小,所以就會加載合適尺寸的圖片給ImageView。從而不用加載完整的圖片。
加載緩慢
加載緩慢的一個主要問題就是當view被移除的時候,還在進行加載圖片和解碼bitmap的任務,因此就有很多我們不需要的任務在執(zhí)行,而Glide可以適時的停止這些任務,只有在視圖對用戶可見的時候才會去加載圖片。
Glide能夠知道Activity和Fragment的生命周期所以知道下載任務什么時候需要被取消掉。
另外一個方式就是內存緩存,我們不用一遍又一遍的解碼bitmap從而節(jié)省了時間。Glide創(chuàng)建一些可配置大小的緩存來捕獲圖片。
它保持兩級的緩存:
- 內存緩存
- 磁盤緩存
當我們給Glide提供一個Url的時候,他會做如下操作:
- 他會檢查以該url為key的圖片是否存在于內存緩存中,并且是否可用
- 如果存在于內存緩存中,他就會從內存緩存中取出加載到view中
- 如果當下不在內存緩存中,就會去檢查磁盤緩存
- 如果存在于磁盤緩存中,則會取出,然后存儲到內存緩存并且加載到View中
- 如果也不存在于磁盤緩存的話,他會從網絡上加載,然后存儲到內存和磁盤,并且加載到view中
UI無響應
UI無響應的一個最重要的原因就是在主線程中做了太多的工作,我們知道渲染UI的所有動作都在主線程中完成,Android每16毫秒就會更新一下UI,如果執(zhí)行任何超過16ms的任務,安卓就會跳過該更新,因此就會導致每秒幀數減少。
如果FPS較低,則用戶看到UI就會無響應,即使在后臺線程加載圖片,也還會如此,這是為什么?
因為如果加載的Bitmap太大,他就會導致內存回收頻繁。
當GC運行的時候,應用就無法運行。
Glide如何解決這個問題呢?
使用Bitmap池。
Glide使用Bitmap池的思想來盡量減少GC的執(zhí)行。
如果使用圖片池就會減少內存的分配和釋放,從而實現應用程序的平滑運行。
如何避免在應用程序中持續(xù)分配和釋放內存呢?
通過使用bitmap的inBitmap屬性,他會重用Bitmap的內存。
使用時的一些限制:
在SDK18及以下,加載的位圖和你重新使用的位圖必須大小一致才能正常工作。
在SDK19及以上,規(guī)則則會稍微放松一些,你的現有的位圖可以比要加載的位圖大或者相同。
對于不同的像素格式使用不同的位圖。
如果我們需要一個接一個的加載兩張圖片,加載第一張的時候會分配內存,當我們不需要第一張的時候,不需要回收bitmap,使用第一張圖片的內存來加載第二張圖片。
接下來看一下代碼:
Bitmap bitmapOne = BitmapFactory.decodeFile(filePathOne);
imageView.setImageBitmap(bitmapOne);
// lets say , we do not need image bitmapOne now and we have to set // another bitmap in imageView
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePathTwo, options);
options.inMutable = true;
options.inBitmap = bitmapOne;
options.inJustDecodeBounds = false;
Bitmap bitmapTwo = BitmapFactory.decodeFile(filePathTwo, options);
imageView.setImageBitmap(bitmapTwo);
這樣我們就不會一次又一次的調用GC。
這里有幾件在不同Android版本中,bubitmap重用時需要考慮的事情.
你可以說bitmap池是不再需要的bitmap列表,但是可以用來重用用以加載新的位圖。