網(wǎng)絡(luò)上有許多關(guān)于UI卡頓優(yōu)化的解析栽惶,但大部分都是簡(jiǎn)單的原理介紹迅脐,例子都比較簡(jiǎn)單芍殖,往往是為了驗(yàn)證UI卡頓而硬造的,不能在實(shí)際場(chǎng)景中應(yīng)用谴蔑。
本文結(jié)合大圖加載豌骏,與UI卡頓優(yōu)化,向大家介紹UI卡頓優(yōu)化的基本原理隐锭。
UI卡頓的根本原因是UI線程無(wú)法在16ms內(nèi)完成UI繪制窃躲。 下面以android大圖加載為例,結(jié)合內(nèi)存分析成榜,systrace框舔,TraceView等分析UI卡頓優(yōu)化.
兩種大圖加載方式對(duì)比
方法1
方法一是鴻洋大神多年前寫的一種使用BitmapRegionDecoder分區(qū)域加載實(shí)現(xiàn)大圖加載的方法,詳情可見以下鏈接
源碼地址可見:自定義大圖加載--LagouBitmap
方法2
方法二基于SubsamplingScaleImageView這個(gè)庫(kù)來(lái)實(shí)現(xiàn)大圖加載赎婚,他主要利用了切片來(lái)實(shí)現(xiàn)大圖加載刘绣,詳細(xì)原理介紹可以見以下鏈接.
Android超長(zhǎng)圖加載與subsampling scale image view實(shí)現(xiàn)分析 使用SubSamplingScaleImageView實(shí)現(xiàn)加載
源碼實(shí)例可見:SubSamplingScaleImageView
內(nèi)存分析
分別使用兩種方式加載圖片,滑動(dòng)后使用Profiler查看內(nèi)存情況
方法1
可以看出方法一存在比較嚴(yán)重的內(nèi)存抖動(dòng)挣输,方法二的內(nèi)存較為平緩 其原因在于方法一在內(nèi)存中創(chuàng)建了對(duì)象纬凤,導(dǎo)致對(duì)象頻繁創(chuàng)建與回收,造成內(nèi)存抖動(dòng)
`protected void onDraw(Canvas canvas) { Bitmap bm = mDecoder.decodeRegion(mRect, options); canvas.drawBitmap(bm, 0, 0, null); }`
systrace分析
方法1
可以看出撩嚼,方法1存在掉幀情況停士,即無(wú)法在16ms內(nèi)完成繪制工作,systraceView提示Long View#draw完丽,即繪制時(shí)間過(guò)長(zhǎng) 而方法2則不存在掉幀情況牡昆,繪制都可以在16ms內(nèi)完成
方法一具體是什么問題導(dǎo)致了無(wú)法在16ms內(nèi)繪制完成兵罢,我們需要在TraceView中詳細(xì)定位一下
TraceView分析
在TraceView中相同顏色的色塊即代表一個(gè)方法的執(zhí)行奔缠,可以清晰的看出圖中主線程有個(gè)方法執(zhí)行時(shí)間過(guò)長(zhǎng) 點(diǎn)擊后在下方會(huì)展示出詳細(xì)的方法名束昵,即BitmapRegionDecoder.decodeRegion方法 可以看出這是個(gè)耗時(shí)操作,在onDraw中反復(fù)調(diào)用decodeRegion方法即是掉幀的原因
總結(jié)
1.在單純使用BitmapRegionDecoder加載大圖時(shí)聘鳞,由于在onDraw中頻繁創(chuàng)建對(duì)象會(huì)造成內(nèi)存抖動(dòng)薄辅,在onDraw中反復(fù)調(diào)用decodeRegion要拂,這是個(gè)耗時(shí)操作,會(huì)導(dǎo)致掉幀
2.而在SubScaleSampleImageView中站楚,將大圖切片脱惰,再判斷是否可見,如果可見則加入內(nèi)存中窿春,否則回收拉一,減少了內(nèi)存占用與抖動(dòng) 同時(shí)根據(jù)不同的縮放比例選擇合適的采樣率,進(jìn)一步減少內(nèi)存占用 同時(shí)在子線程進(jìn)行decodeRegion操作谁尸,解碼成功后回調(diào)至主線程舅踪,減少UI卡頓.
本文轉(zhuǎn)自 https://juejin.cn/post/6870389004387385352纽甘,如有侵權(quán)良蛮,請(qǐng)聯(lián)系刪除。