1.UI卡頓有可能是UI布局過(guò)于復(fù)雜,無(wú)法在16ms內(nèi)繪制一幀導(dǎo)致冲簿;可以使用HierarchyViewer來(lái)查找布局是否過(guò)于復(fù)雜粟判,還可以使用TraceView來(lái)觀察CPU的執(zhí)行情況,更加快捷的找到性能瓶頸峦剔。
2.Overdraw(過(guò)度繪制)問(wèn)題档礁,就是同一個(gè)區(qū)域被多次繪制,通過(guò)手機(jī)設(shè)置里面的開(kāi)發(fā)者選項(xiàng)吝沫,打開(kāi)Show GPU Overdraw的選項(xiàng)呻澜,可以觀察UI上的Overdraw情況。藍(lán)色(繪制1次)惨险,淡綠(繪制2次)羹幸,淡紅(繪制3次),深紅(繪制4次)代表了4種不同程度的Overdraw情況辫愉,我們的目標(biāo)就是盡量減少紅色Overdraw栅受,看到更多的藍(lán)色區(qū)域。
3.打開(kāi)手機(jī)里面的開(kāi)發(fā)者選項(xiàng)一屋,選擇Profile GPU Rendering窘疮,選中On screen as bars的選項(xiàng)。通過(guò)這個(gè)工具查看每一幀繪制的時(shí)間冀墨。
4.自定義view時(shí)通過(guò)canvas.clipRect()來(lái)確定需要刷新的區(qū)域闸衫,選定區(qū)域外的地方刷新繪制時(shí)會(huì)被忽略,以此來(lái)減少Overdraw提升流暢度诽嘉。還可以使用canvas.quickreject()來(lái)判斷是否沒(méi)和某個(gè)矩形相交蔚出,從而跳過(guò)那些非矩形區(qū)域內(nèi)的繪制操作。
5.java內(nèi)存回收GC調(diào)用的時(shí)候會(huì)暫停所有的線程虫腋,包括UI線程骄酗,所以頻繁的調(diào)用GC也會(huì)感覺(jué)到卡頓。導(dǎo)致GC頻繁調(diào)用的原因可能是:內(nèi)存抖動(dòng)即大量的對(duì)象被創(chuàng)建又在短時(shí)間內(nèi)馬上被釋放悦冀;瞬間產(chǎn)生大量的對(duì)象會(huì)占用大量Young Generation的內(nèi)存區(qū)域趋翻,達(dá)到閥值時(shí)剩余空間不夠會(huì)觸發(fā)GC。解決辦法盒蟆,在Memory Monitor里面查如果短時(shí)間發(fā)生了多次內(nèi)存的漲跌踏烙,這意味著很有可能發(fā)生了內(nèi)存抖動(dòng)。代碼規(guī)避的點(diǎn)有:避免在for循環(huán)里面分配對(duì)象占用內(nèi)存历等;避免在onDraw方法里面執(zhí)行復(fù)雜的操作讨惩,避免創(chuàng)建對(duì)象;對(duì)于無(wú)法避免的需要頻繁創(chuàng)建的可以考慮使用對(duì)象池寒屯,但是對(duì)象池需要在不用時(shí)自己手動(dòng)進(jìn)行銷毀荐捻。
6.有動(dòng)畫需要對(duì)Bitmap繪制時(shí)可以通過(guò)拆分,只單獨(dú)繪制需要變化的部分,可以通過(guò)setLayerType()方法使得這個(gè)View強(qiáng)制用Hardware來(lái)進(jìn)行渲染处面。對(duì)于動(dòng)畫使用PropertyAnimation或者ViewAnimation來(lái)操作實(shí)現(xiàn)厂置,Android系統(tǒng)對(duì)這些Animation做過(guò)一定的優(yōu)化處理。
7.減少for each的遍歷使用魂角,耗費(fèi)時(shí)間較多的一種遍歷方法农渊。
8.緩存算法,android最常用的一個(gè)緩存算法是LRU(Least Recently Use)或颊;需要注意LRU Cache中被淘汰對(duì)象的回收,否者會(huì)引起嚴(yán)重的內(nèi)存泄露传于。LruCache的構(gòu)建:
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
intavailMemInBytes? = am.getMemoryClass()*1024*1024/8;//LruCache最合適的大小
LruCache bitMapCache =newLruCache(availMemInBytes){
? ? @Override
? ? protected intsizeOf(String key,Bitmap value) {
? ? ? ? //讓Cache知道每個(gè)加入的Item的具體大小
? ? ? ? returnvalue.getByteCount();
? ? }
};
9.試用Android Studio中工具欄的Analysis -> Inspect Code的Lint囱挑,靜態(tài)掃描應(yīng)用源碼并找出其中的潛在問(wèn)題。
10.view如果不設(shè)置透明度繪制一次沼溜,如果設(shè)置了透明度繪制時(shí)至少會(huì)繪制兩次平挑。解決辦法直接用GPU進(jìn)行繪制,具體參考Hidden Cost of Transparency
11.提高自定義view的性能的方法:僅僅在View的內(nèi)容發(fā)生改變的時(shí)候才去觸發(fā)invalidate方法系草,盡量使用ClipRect等方法來(lái)提高繪制的性能通熄;減少繪制時(shí)不必要的繪制元素,對(duì)于那些不可見(jiàn)的元素找都,我們需要盡量避免重繪唇辨;對(duì)于不在屏幕上的元素,可以使用Canvas.quickReject把他們給剔除能耻,避免浪費(fèi)CPU資源赏枚。另外盡量使用GPU來(lái)進(jìn)行UI的渲染,這樣能夠極大的提高程序的整體表現(xiàn)性能薯蝎。
12.圖片不同的解碼率占用的內(nèi)存大小也不一樣挤聘,選擇合適的解碼率可以防止oom的出現(xiàn)微猖。
BitmapFactory.Options options =newBitmapFactory.Options();
options.inPreferredConfig= Bitmap.Config.ARGB_8888;//需要的內(nèi)存最大每個(gè)像素占8位
options.inPreferredConfig= Bitmap.Config.ARGB_4444;//每個(gè)像素占4位
options.inPreferredConfig= Bitmap.Config.RGB_565;//沒(méi)有透明度R占5位 G占6位 B占5位
options.inPreferredConfig= Bitmap.Config.ALPHA_8;
13.createScaledBitmap()可以快速的創(chuàng)建縮放的圖片但是需要圖片已經(jīng)加載到內(nèi)存中;options.inSampleSize屬性同樣可以實(shí)現(xiàn)縮放并且不用將圖片加載到內(nèi)存中栗恩;使用inScaled,inDensity洪燥,inTargetDensity的屬性來(lái)對(duì)解碼圖片做處理也可以實(shí)現(xiàn)縮放磕秤;options.inJustDecodeBounds=true可以在不將圖片加載到內(nèi)存中的前提下讀取圖片的寬高等信息;
14.使用bitmapFactoryOptions.inBitmap屬性來(lái)提高bitmap的循環(huán)試用蚓曼,減少內(nèi)存開(kāi)銷亲澡;使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經(jīng)存在的內(nèi)存區(qū)域,新解碼的bitmap會(huì)嘗試去使用之前那張bitmap在heap中所占據(jù)的pixel data內(nèi)存區(qū)域纫版,而不是去問(wèn)內(nèi)存重新申請(qǐng)一塊區(qū)域來(lái)存放bitmap床绪。試用限制:在SDK 11 -> 18之間,重用的bitmap大小必須是一致的,例如給inBitmap賦值的圖片大小為100-100癞己,那么新申請(qǐng)的bitmap必須也為100-100才能夠被重用膀斋。從SDK 19開(kāi)始,新申請(qǐng)的bitmap大小必須小于或者等于已經(jīng)賦值過(guò)的bitmap大斜匝拧仰担;新申請(qǐng)的bitmap與舊的bitmap必須有相同的解碼格式,例如大家都是8888的绩社,如果前面的bitmap是8888摔蓝,那么就不能支持4444與565格式的bitmap了。
15.ArrayMap比HasMap更加的節(jié)省內(nèi)存愉耙,遍歷效率也比較高贮尉。但是數(shù)據(jù)最好不要超過(guò)千級(jí)。
16.Android中不推薦使用枚舉(Enum)朴沿,和靜態(tài)常量相比猜谚,枚舉會(huì)耗費(fèi)更多的內(nèi)存,編譯后的文件也更大赌渣。
17.通常魏铅,View會(huì)保持Activity的引用,Activity同時(shí)還和其他內(nèi)部對(duì)象也有可能保持引用關(guān)系坚芜。當(dāng)屏幕發(fā)生旋轉(zhuǎn)的時(shí)候览芳,activity很容易發(fā)生泄漏,這樣的話鸿竖,里面的view也會(huì)發(fā)生泄漏路操。避免的規(guī)則有:避免使用異步回調(diào),異步回調(diào)執(zhí)行時(shí)可能activity已經(jīng)被銷毀千贯;避免使用Static對(duì)象屯仗,static的生命周期過(guò)長(zhǎng),使用不當(dāng)很可能導(dǎo)致leak搔谴;避免把View添加到?jīng)]有清除機(jī)制的容器里面如:WeekHashMap魁袜。
本文章是閱讀胡凱同學(xué)的性能優(yōu)系列文章做出的筆記,特此聲明敦第。