1、應(yīng)用卡頓的原理,以及針對(duì)界面切換卡頓和屏幕滑動(dòng)卡頓提出典型的解決思路
卡頓原理:
1)大多數(shù)手機(jī)的屏幕刷新頻率是60hz,如果在1000/60=16.67ms內(nèi)沒(mé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通常存在的問(wèn)題的原因是存在非必需的視圖組件,它不僅僅會(huì)帶來(lái)重復(fù)的計(jì)算操作,而且還會(huì)占用額外的GPU資源。

3)針對(duì)原理來(lái)作出解釋如何優(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)目中說(shuō)出幾種內(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)沒(méi)有辦法把service所占用的RAM空間騰出來(lái)讓給其他組件,另外service還不能被paged out。這減少了系統(tǒng)能夠存放到LRU緩存當(dāng)中的進(jìn)程數(shù)量,它會(huì)影響app之間的切換效率。它甚至?xí)?dǎo)致系統(tǒng)內(nèi)存使用不穩(wěn)定,從而無(wú)法繼續(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)化過(guò)的容器類,例如SparseArray,SparseBooleanArray, 與LongSparseArray。 通常的HashMap的實(shí)現(xiàn)方式更加消耗內(nèi)存,因?yàn)樗枰粋€(gè)額外的實(shí)例對(duì)象來(lái)記錄Mapping操作。另外,SparseArray更加高效在于他們避免了對(duì)key與value的autobox自動(dòng)裝箱,并且避免了裝箱后的解箱。
4) 請(qǐng)注意內(nèi)存開銷
對(duì)你所使用的語(yǔ)言與庫(kù)的成本與開銷有所了解,從開始到結(jié)束,在設(shè)計(jì)你的app時(shí)謹(jǐn)記這些信息。通常,表面上看起來(lái)無(wú)關(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的陷阱。如果沒(méi)有一個(gè)合適的庫(kù)與你的需求相吻合,你應(yīng)該考慮自己去實(shí)現(xiàn),而不是導(dǎo)入一個(gè)大而全的解決方案
6)使用ProGuard來(lái)剔除不需要的代碼
7)避免在內(nèi)部調(diào)用Getters/Setters方法
在Android上這個(gè)技巧就不再是那么的受推崇了,因?yàn)樽侄嗡褜ひ确椒ㄕ{(diào)用效率高得多,我們直接訪問(wèn)某個(gè)字段可能要比通過(guò)getters方法來(lái)去訪問(wèn)這個(gè)字段快3到7倍
8)使用增強(qiáng)型for循環(huán)語(yǔ)法
9)避免創(chuàng)建不必要的對(duì)象
因此請(qǐng)盡量避免創(chuàng)建不必要的對(duì)象,有下面一些例子來(lái)說(shuō)明這個(gè)問(wèn)題:
你需要返回一個(gè)String對(duì)象,并且你知道它最終會(huì)需要連接到一個(gè)StringBuffer,請(qǐng)修改你的函數(shù)實(shí)現(xiàn)方式,避免直接進(jìn)行連接操作,應(yīng)該采用創(chuàng)建一個(gè)臨時(shí)對(duì)象來(lái)做字符串的拼接這個(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ù)組用來(lái)存放(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 的速度是一樣的??臻g而言,double 是兩倍float的大小。在空間不是問(wèn)題的情況下,你應(yīng)該使用 double 。