Android性能優(yōu)化相關(guān)
1. UI卡頓的原因俭识,如何優(yōu)化弦牡?
View的繪制幀數(shù)保持60fps最佳渺氧,這要求沒幀繪制時(shí)間不超過(guò)16ms旨涝,如果不能在16ms內(nèi)完成界面的渲染,那么就會(huì)出現(xiàn)卡頓的現(xiàn)象侣背。
卡頓原因分析:
- UI線程中做了耗時(shí)操作白华,導(dǎo)致UI線程卡頓
- 布局層次嵌套過(guò)多,過(guò)于復(fù)雜贩耐,無(wú)法在16ms內(nèi)完成渲染
- 同一時(shí)間動(dòng)畫執(zhí)行的次數(shù)過(guò)多弧腥,導(dǎo)致CPU和GPU負(fù)載過(guò)重
- overDraw,導(dǎo)致像素在同一幀的時(shí)間內(nèi)被繪制多次
- view頻繁的觸發(fā)measure潮太、layout管搪,導(dǎo)致measure、layout類似耗時(shí)過(guò)多和整個(gè)view頻繁重新渲染
- 頻繁觸發(fā)GC铡买,使得16ms無(wú)法完成繪制
- ANR
優(yōu)化:
- 布局優(yōu)化
- 刪除無(wú)用的布局和層級(jí)更鲁,選擇性使用性能較低的ViewGroup,如RelativeLayout(會(huì)對(duì)子View做兩次Measure奇钞,因?yàn)橛幸蕾囮P(guān)系澡为,所以橫向豎向分別要進(jìn)行一次排序測(cè)量)。
- 使用
include
景埃,merge
標(biāo)簽和Viewstub
媒至。include
、merge
標(biāo)簽可以降低布局的層級(jí)谷徙;Viewstub
提供了按需加載拒啰,需要時(shí)才將布局加載到內(nèi)存中,提高了程序初始化的效率完慧。
- 繪制優(yōu)化
- onDraw中不要?jiǎng)?chuàng)建新的局部對(duì)象(因?yàn)閛nDraw方法可能會(huì)被頻繁調(diào)用谋旦,瞬間產(chǎn)生大量對(duì)象,占用過(guò)多內(nèi)存以及導(dǎo)致系統(tǒng)更加頻繁GC,降低效率)
- onDraw不要做耗時(shí)的任務(wù)蛤织,不要做過(guò)多的循環(huán)操作赴叹。
2. 內(nèi)存泄漏,內(nèi)存泄漏有哪些影響指蚜?常見的內(nèi)存泄漏有哪些乞巧?怎么檢測(cè)內(nèi)存泄漏的?
內(nèi)存泄漏:指程序分配出去的內(nèi)存不再使用摊鸡,無(wú)法進(jìn)行回收绽媒。
延伸:非靜態(tài)內(nèi)部類天然持有外部類的引用;靜態(tài)內(nèi)部類不持有外部類的引用免猾。
影響:
- 應(yīng)用可用內(nèi)存減少是辕,增加堆內(nèi)存壓力
- 頻繁觸發(fā)GC,會(huì)降低應(yīng)用的性能
- 到一定程度會(huì)導(dǎo)致內(nèi)存溢出的錯(cuò)誤
常見的內(nèi)存泄漏:(括號(hào)里面為解決辦法)
- 靜態(tài)變量持有Activity的上下文 (減少使用static)
- 單例造成的內(nèi)存泄漏(使用Application的Context)
- 匿名內(nèi)部類與非靜態(tài)內(nèi)部類持有外部類的引用造成的(非靜態(tài)內(nèi)部類轉(zhuǎn)換為靜態(tài)內(nèi)部類+弱引用)
- 各種注冊(cè)的監(jiān)聽器猎提,沒有解注冊(cè)(在onDestroy里面取消注冊(cè))
- Handler造成的(Handler持有的引用最好使用弱引用获三,在Activity被釋放的時(shí)候要記得清空Message,取消Handler對(duì)象的)
- 資源對(duì)象未關(guān)閉锨苏,例如IO疙教,數(shù)據(jù)庫(kù),Bitmap(及時(shí)關(guān)閉資源)
- 屬性動(dòng)畫中無(wú)限循環(huán)的未取消(及時(shí)取消動(dòng)畫)
如何檢測(cè)內(nèi)存泄漏:AS monitor伞租、MAT贞谓、LeakCanary
數(shù)據(jù)結(jié)構(gòu)相關(guān)
1.數(shù)組與鏈表的區(qū)別
數(shù)組 | 鏈表 | |
---|---|---|
特點(diǎn) | 在內(nèi)存中是一塊連續(xù)的區(qū)域,使用前需要申請(qǐng)內(nèi)存的大小葵诈,有可能造成內(nèi)存的浪費(fèi)裸弦。知道每一個(gè)數(shù)據(jù)的內(nèi)存地址;是從棧分配的 | 在內(nèi)存中可以存在任何地方作喘,不要求連續(xù)理疙。每一個(gè)數(shù)據(jù)都保存了下一個(gè)數(shù)據(jù)的內(nèi)存地址。從堆中分配的徊都。 |
優(yōu)點(diǎn) | 隨機(jī)訪問性強(qiáng)沪斟;查找速度快 | 插入刪除速度快;內(nèi)存利用率高暇矫,不會(huì)浪費(fèi)內(nèi)存主之;大小沒有固定,擴(kuò)展很靈活李根; |
缺點(diǎn) | 插入和刪除的效率低槽奕;可能會(huì)浪費(fèi)內(nèi)存;內(nèi)存空間要求高房轿,必須有足夠的連續(xù)內(nèi)存空間粤攒;數(shù)組大小固定所森,不能動(dòng)態(tài)擴(kuò)展。 | 不能隨機(jī)查找夯接,必須從第一個(gè)開始遍歷焕济,查找效率低。 |
各種細(xì)節(jié)問題收集及解答
-
擴(kuò)大view的點(diǎn)擊區(qū)域怎么做盔几?
- 將點(diǎn)擊事件寫在父View上
- 增加padding晴弃,適合圖片等dp或px為單位的view,不適合textview逊拍,button等包含sp計(jì)算單位的view
- 通過(guò)TouchDelegate來(lái)擴(kuò)大view的點(diǎn)擊區(qū)域
-
requestLayout和invalide的區(qū)別
requestLayout會(huì)從View樹重新進(jìn)行一次測(cè)量上鞠、布局、繪制芯丧;invalidate只會(huì)開始View樹的繪制(只繪制需要重繪的視圖)芍阎,在UI線程中調(diào)用;postInvalidate是在非UI線程中調(diào)用缨恒。
-
LRUCache
(最近最少使用算法)的原理LRU是近期最少使用的算法谴咸,它的核心思想是當(dāng)緩存滿時(shí),會(huì)優(yōu)先淘汰那些近期最少使用的緩存對(duì)象肿轨。
緩存策略分為添加寿冕、獲取和刪除蕊程,為什么需要?jiǎng)h除緩存呢椒袍?因?yàn)槊總€(gè)設(shè)備都會(huì)有一定的容量限制,當(dāng)容量滿了的話就需要?jiǎng)h除藻茂。
LRUCache是個(gè)泛型類驹暑,主要算法原理是把最近使用的對(duì)象用強(qiáng)引用存儲(chǔ)在LinkedHashMap中。當(dāng)緩存滿時(shí)辨赐,把最近最少使用的對(duì)象從內(nèi)存中移除优俘,并提供了get和put方法來(lái)完成緩存的存取和添加操作。
一些性能優(yōu)化建議
- 避免創(chuàng)建過(guò)多的對(duì)象
- 不要過(guò)多使用枚舉掀序,枚舉占用的內(nèi)存空間要比整型大
- 常量請(qǐng)使用static final來(lái)修飾
- 使用一些Android特有的數(shù)據(jù)結(jié)構(gòu)帆焕,比如SparseArray和Pair等,它們都具有更好的性能
- 適當(dāng)使用軟引用和弱引用
- 采用內(nèi)存緩存和磁盤緩存
- 盡量采用靜態(tài)內(nèi)部類不恭,這樣可以避免潛在的由于內(nèi)部類而導(dǎo)致的內(nèi)存泄漏