Glide如何優(yōu)化內(nèi)存消耗

1_kIIujuf1aYUVbJhJiDKiPA.png

前言

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
DDDD.png

我們有哪些解決辦法?

選擇正確的質(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_8888RGB_565位圖的區(qū)別

1_Vxx8-JnzenuseG7jZreoPA.png

GlideModule是Glide提供的一個(gè)配置接口,它會(huì)在第一次使用Glide的時(shí)候被調(diào)用,用于進(jìn)行Glide的一些初始配置

具體 GlideModule 的使用呢袱,可以參見官方文檔:

github.com/bumptech/gl…

修改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 少了一半

AAAA.png

圖片尺寸也很重要

當(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
BBB.png

同時(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
CCC.png

我們可以看到, 我們的原圖大小為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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末她我,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子迫横,更是在濱河造成了極大的恐慌番舆,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矾踱,死亡現(xiàn)場(chǎng)離奇詭異恨狈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)呛讲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門禾怠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來返奉,“玉大人,你說我怎么就攤上這事吗氏⊙科” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵弦讽,是天一觀的道長(zhǎng)污尉。 經(jīng)常有香客問我,道長(zhǎng)坦袍,這世上最難降的妖魔是什么十厢? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任等太,我火速辦了婚禮捂齐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缩抡。我一直安慰自己奠宜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布瞻想。 她就那樣靜靜地躺著压真,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蘑险。 梳的紋絲不亂的頭發(fā)上滴肿,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音佃迄,去河邊找鬼泼差。 笑死,一個(gè)胖子當(dāng)著我的面吹牛呵俏,可吹牛的內(nèi)容都是我干的堆缘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼普碎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼吼肥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起麻车,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤缀皱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后动猬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啤斗,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年枣察,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了争占。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片燃逻。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖臂痕,靈堂內(nèi)的尸體忽然破棺而出伯襟,到底是詐尸還是另有隱情,我是刑警寧澤握童,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布姆怪,位于F島的核電站,受9級(jí)特大地震影響澡绩,放射性物質(zhì)發(fā)生泄漏稽揭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一肥卡、第九天 我趴在偏房一處隱蔽的房頂上張望溪掀。 院中可真熱鬧,春花似錦步鉴、人聲如沸揪胃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)喊递。三九已至,卻和暖如春阳似,著一層夾襖步出監(jiān)牢的瞬間骚勘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工撮奏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留俏讹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓挽荡,卻偏偏與公主長(zhǎng)得像藐石,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子定拟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354