1泣特、應(yīng)用卡頓的原理柿菩,以及針對(duì)界面切換卡頓和屏幕滑動(dòng)卡頓提出典型的解決思路
卡頓原理:
1)大多數(shù)手機(jī)的屏幕刷新頻率是60hz部凑,如果在1000/60=16.67ms內(nèi)沒有辦法把這一幀的任務(wù)執(zhí)行完畢椭员,就會(huì)發(fā)生丟幀的現(xiàn)象车海。丟幀越多,用戶感受到的卡頓情況就越嚴(yán)重隘击。
2)渲染操作通常依賴于兩個(gè)核心組件:CPU與GPU侍芝。CPU負(fù)責(zé)包括Measure,Layout埋同,Record州叠,Execute的計(jì)算操作,GPU負(fù)責(zé)Rasterization(柵格化)操作凶赁。CPU通常存在的問題的原因是存在非必需的視圖組件咧栗,它不僅僅會(huì)帶來重復(fù)的計(jì)算操作,而且還會(huì)占用額外的GPU資源虱肄。
3)針對(duì)原理來作出解釋如何優(yōu)化
3.1、減少視圖的層級(jí)結(jié)構(gòu)
3.2咏窿、移除Window默認(rèn)的background
3.3石洗、移除XML布局文件中非必需的background
3.4提茁、按需顯示占位背景圖片
3.5、優(yōu)化自定義View的ondraw方法
3.6、ListView滑動(dòng)取消圖片加載
3.7丧蘸、ListView采用ViewHolder
2别惦、android中如何優(yōu)化內(nèi)存允趟,針對(duì)項(xiàng)目中說出幾種內(nèi)存優(yōu)化方案
Android Studio中的Memory Monitor可以很好的幫助我們查看程序的內(nèi)存使用情況屎慢。
1) 珍惜Services資源
當(dāng)你啟動(dòng)一個(gè)service,系統(tǒng)會(huì)傾向?yàn)榱吮A暨@個(gè)service而一直保留service所在的進(jìn)程咽块。這使得進(jìn)程的運(yùn)行代價(jià)很高绘面,因?yàn)橄到y(tǒng)沒有辦法把service所占用的RAM空間騰出來讓給其他組件,另外service還不能被paged out。這減少了系統(tǒng)能夠存放到LRU緩存當(dāng)中的進(jìn)程數(shù)量揭璃,它會(huì)影響app之間的切換效率晚凿。它甚至?xí)?dǎo)致系統(tǒng)內(nèi)存使用不穩(wěn)定,從而無法繼續(xù)保持住所有目前正在運(yùn)行的service瘦馍。
限制你的service的最好辦法是使用IntentService歼秽, 它會(huì)在處理完交代給它的intent任務(wù)之后盡快結(jié)束自己
2) 避免bitmaps的浪費(fèi)
當(dāng)你加載一個(gè)bitmap時(shí),僅僅需要保留適配當(dāng)前屏幕設(shè)備分辨率的數(shù)據(jù)即可情组,如果原圖高于你的設(shè)備分辨率燥筷,需要做縮小的動(dòng)作。請(qǐng)記住院崇,增加bitmap的尺寸會(huì)對(duì)內(nèi)存呈現(xiàn)出2次方的增加肆氓,因?yàn)閄與Y都在增加。
3) 使用優(yōu)化的數(shù)據(jù)容器
利用Android Framework里面優(yōu)化過的容器類底瓣,例如SparseArray,SparseBooleanArray, 與LongSparseArray谢揪。 通常的HashMap的實(shí)現(xiàn)方式更加消耗內(nèi)存,因?yàn)樗枰粋€(gè)額外的實(shí)例對(duì)象來記錄Mapping操作捐凭。另外拨扶,SparseArray更加高效在于他們避免了對(duì)key與value的autobox自動(dòng)裝箱,并且避免了裝箱后的解箱柑营。
4) 請(qǐng)注意內(nèi)存開銷
對(duì)你所使用的語言與庫(kù)的成本與開銷有所了解,從開始到結(jié)束村视,在設(shè)計(jì)你的app時(shí)謹(jǐn)記這些信息官套。通常,表面上看起來無關(guān)痛癢(innocuous)的事情也許實(shí)際上會(huì)導(dǎo)致大量的開銷蚁孔。例如:
Enums的內(nèi)存消耗通常是static constants的2倍奶赔。你應(yīng)該盡量避免在Android上使用enums。
在Java中的每一個(gè)類(包括匿名內(nèi)部類)都會(huì)使用大概500 bytes杠氢。
每一個(gè)類的實(shí)例花銷是12-16 bytes站刑。
往HashMap添加一個(gè)entry需要額一個(gè)額外占用的32 bytes的entry對(duì)象。
5) 謹(jǐn)慎使用第三方libraries
不要陷入為了1個(gè)或者2個(gè)功能而導(dǎo)入整個(gè)library的陷阱鼻百。如果沒有一個(gè)合適的庫(kù)與你的需求相吻合绞旅,你應(yīng)該考慮自己去實(shí)現(xiàn),而不是導(dǎo)入一個(gè)大而全的解決方案
6)使用ProGuard來剔除不需要的代碼
7)避免在內(nèi)部調(diào)用Getters/Setters方法
在Android上這個(gè)技巧就不再是那么的受推崇了温艇,因?yàn)樽侄嗡褜ひ确椒ㄕ{(diào)用效率高得多因悲,我們直接訪問某個(gè)字段可能要比通過getters方法來去訪問這個(gè)字段快3到7倍
8)使用增強(qiáng)型for循環(huán)語法
9)避免創(chuàng)建不必要的對(duì)象
因此請(qǐng)盡量避免創(chuàng)建不必要的對(duì)象,有下面一些例子來說明這個(gè)問題:
你需要返回一個(gè)String對(duì)象勺爱,并且你知道它最終會(huì)需要連接到一個(gè)StringBuffer晃琳,請(qǐng)修改你的函數(shù)實(shí)現(xiàn)方式,避免直接進(jìn)行連接操作,應(yīng)該采用創(chuàng)建一個(gè)臨時(shí)對(duì)象來做字符串的拼接這個(gè)操作卫旱。
當(dāng)從已經(jīng)存在的數(shù)據(jù)集中抽取出String的時(shí)候人灼,嘗試返回原數(shù)據(jù)的substring對(duì)象,而不是創(chuàng)建一個(gè)重復(fù)的對(duì)象顾翼。使用substring的方式投放,你將會(huì)得到一個(gè)新的String對(duì)象,但是這個(gè)string對(duì)象是和原string共享內(nèi)部char[]空間的暴构。
一組int數(shù)據(jù)要比一組Integer對(duì)象要好很多跪呈。可以得知取逾,兩組一維數(shù)組要比一個(gè)二維數(shù)組更加的有效率耗绿。同樣的,這個(gè)道理可以推廣至其他原始數(shù)據(jù)類型砾隅。
如果你需要實(shí)現(xiàn)一個(gè)數(shù)組用來存放(Foo,Bar)的對(duì)象误阻,記住使用Foo[]與Bar[]要比(Foo,Bar)好很多。(例外的是晴埂,為了某些好的API的設(shè)計(jì)究反,可以適當(dāng)做一些妥協(xié)。但是在自己的代碼內(nèi)部儒洛,你應(yīng)該多多使用分解后的容易)精耐。
10)常量聲明為Static Final
11)避免使用float類型
Android系統(tǒng)中float類型的數(shù)據(jù)存取速度是int類型的一半,盡量?jī)?yōu)先采用int類型琅锻。
就速度而言卦停,現(xiàn)代硬件上,float 和 double 的速度是一樣的恼蓬【辏空間而言,double 是兩倍float的大小处硬。在空間不是問題的情況下小槐,你應(yīng)該使用 double 。