前言
Glide是Google官方推薦的一款圖片加載庫(kù),使用起來非常的簡(jiǎn)單便利,通常我們最簡(jiǎn)單的調(diào)用如下
Glide.with(this).load(imageUrl).into(image)
但是在使用Glide時(shí)候,我們可以通過一些設(shè)置來優(yōu)化內(nèi)存占用,避免界面出現(xiàn)卡頓或者OOM, 例如:一個(gè)購(gòu)物網(wǎng)站的商品詳情頁(yè)有好幾十張超大圖(運(yùn)營(yíng)配置的大圖一般都是高清相機(jī)直接上傳的,后臺(tái)也沒有做圖片限制),這個(gè)時(shí)候當(dāng)我們上下滑動(dòng)商品詳情頁(yè)會(huì)很明顯出現(xiàn)卡頓,或者是我們無限制的通過猜你喜歡打開很多個(gè)商品詳情頁(yè),這個(gè)時(shí)候我們通過Android Studio自帶Profiler內(nèi)存檢測(cè)工具可以很明顯的看到我們的內(nèi)存很快達(dá)到極限.
我們使用最基礎(chǔ)的方式加載一張大小為4665600 byte
的圖片
Glide.with(this)
.load(imageUrl)
.skipMemoryCache(true)
.addListener(object : RequestListener<Drawable>{
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
smartLog {
"Glide---onLoadFailed--$e"
}
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
val bd = resource as BitmapDrawable
val bitmap = bd.bitmap
result.text = "圖片SIze ${bitmap.byteCount} byte"
smartLog {
"Glide---onResourceReady--圖片SIze ${bitmap.byteCount} byte"
}
return false
}
}).into(image)
通過logger日志看看最終我們拿到的圖片大小
GlideTestActivity$onClick$1;Glide---onResourceReady--圖片SIze 4665600 byte
我們有哪些解決辦法?
選擇正確的質(zhì)量(RGB)
默認(rèn)情況下,色彩度為 ARGB_8888 圖片旧噪,每像素會(huì)占用 4 bytes 的大小。Glide V3使用RGB_565
位圖格式,它需要每個(gè)像素 2 bytes ,內(nèi)存占用是ARGB_8888
的一半, 最新的Glide V4默認(rèn)使用的是ARGB_8888
格式
我們通過下圖看看ARGB_8888
和RGB_565
位圖的區(qū)別
GlideModule是Glide提供的一個(gè)配置接口,它會(huì)在第一次使用Glide的時(shí)候被調(diào)用,用于進(jìn)行Glide的一些初始配置
具體 GlideModule 的使用呢袱,可以參見官方文檔:
修改GlideV4默認(rèn)配置
@GlideModule
class CustomGlideModuleV4 : AppGlideModule() {
override fun applyOptions(context: Context, builder: GlideBuilder) {
builder.setDefaultRequestOptions(
RequestOptions().format(DecodeFormat.PREFER_RGB_565))
}
}
修改Glide V3默認(rèn)配置
class CustomGlideModuleV3 : GlideModule {
fun applyOptions(context: Context, builder: GlideBuilder) {
builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888); //default in v3 is RGB_565
}
fun registerComponents(context: Context, glide: Glide) {
}
}
使用RGB_565替代ARGB_8888的缺點(diǎn)
RGB_565不支持透明度,如果我們的圖片不支持透明度并且節(jié)省內(nèi)存的話還是可以替代的
RGB_565可能還存在一些別的問題, 例如圖像包含漸變,你有可能會(huì)發(fā)現(xiàn)顏色的陰影之間會(huì)突然發(fā)生變化
-
在Glide v3中柬甥,具有RGB_565質(zhì)量的白色圖像可能顯示為淡黃色而不是白色霹期。 Glide v4中沒有出現(xiàn)此問題
1_9FBi_-Gih0xhjsuItjvumg.png
GlideV4使用RGB_565加載大圖
Glide.with(this)
.load(imageUrl)
.skipMemoryCache(true)
.format(DecodeFormat.PREFER_RGB_565)
.addListener(object : RequestListener<Drawable>{
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
smartLog {
"Glide---onLoadFailed--$e"
}
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
val bd = resource as BitmapDrawable
val bitmap = bd.bitmap
result.text = "圖片SIze ${bitmap.byteCount} byte"
smartLog {
"Glide---onResourceReady--圖片SIze ${bitmap.byteCount} byte"
}
return false
}
}).into(image)
通過logger日志看看最終我們拿到的圖片大小
GlideTestActivity$onClick$3;Glide---onResourceReady--圖片SIze 2985984 byte
可以看到我們拿到的圖片size比原圖大小4665600 byte
少了一半
圖片尺寸也很重要
當(dāng)然疹鳄,加載的位圖的大小不僅取決于其質(zhì)量,還取決于大小犀农。 在ImageView中顯示圖像之前龄广,Glide調(diào)整其大小硫眯,使其適合目標(biāo)尺寸,以實(shí)現(xiàn)最佳的內(nèi)存占用蜀细。 但是舟铜,有關(guān)Glide如何工作的一些事情值得了解,沒必要將大位圖加載到內(nèi)存中奠衔。
Glide.with(this)
.load(imageUrl)
.skipMemoryCache(true)
.override(((getScreenWidth(this)*0.8).toInt()), ((getScreenHeight(this)*0.8).toInt()))
.addListener(object : RequestListener<Drawable>{
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
smartLog {
"Glide---onLoadFailed--$e"
}
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
smartLog {
"Glide---onResourceReady--$resource"
}
val bd = resource as BitmapDrawable
val bitmap = bd.bitmap
result.text = "圖片Size ${bitmap.byteCount} byte"
return false
}
}).into(image)
我們通過logger日志看看最終我們拿到的圖片大小
GlideTestActivity$onClick$2;Glide---onResourceReady--圖片SIze 2332800 byte
同時(shí)調(diào)整像素RGB_565以及圖片大小(原圖大小的0.8倍)
Glide.with(this)
.load(imageUrl)
.skipMemoryCache(true)
.override(((getScreenWidth(this)*0.8).toInt()), ((getScreenHeight(this)*0.8).toInt()))
.format(DecodeFormat.PREFER_RGB_565)
.addListener(object : RequestListener<Drawable>{
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
smartLog {
"Glide---onLoadFailed--$e"
}
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
val bd = resource as BitmapDrawable
val bitmap = bd.bitmap
result.text = "圖片SIze ${bitmap.byteCount} byte "
smartLog {
"Glide---onResourceReady--圖片SIze ${bitmap.byteCount} byte"
}
return false
}
}).into(image)
我們通過logger日志看看最終我們拿到的圖片大小
GlideTestActivity$onClick$4;Glide---onResourceReady--圖片SIze 1492992 byte
我們可以看到, 我們的原圖大小為4665600
,我們使用上述兩種方式解決之后圖片大小變?yōu)榱?code>1492992
調(diào)整完的效果還是非常棒的,美女還是那樣的漂亮,只有后邊背景顏色有些許的減淡,但是我們大幅度降低圖片內(nèi)存占用,為了我們手機(jī)性能的大幅度提高這點(diǎn)質(zhì)量上的損失還是可以接受的(除非UI設(shè)計(jì)師太苛刻).
Glide是一個(gè)很棒的庫(kù)谆刨,可以輕松加載圖像。 但是归斤,有時(shí)候最好知道它如何以最有效的內(nèi)存方式使用痊夭。 我希望我在本文中描述的事實(shí)將幫助您減少應(yīng)用程序的內(nèi)存占用,并避免一些邪惡的OOM錯(cuò)誤脏里。
參考文章
https://proandroiddev.com/how-to-optimize-memory-consumption-when-using-glide-9ac984cfe70f