標籤:
Android效能最佳化典範
1、大多數使用者感知到的卡頓等效能問題的最主要根源都是因為渲染效能。
從設計師的角度,他們希望App能夠有更多的動畫,圖片等時尚元素來實現流暢的使用者體驗。
但是Android系統很有可能無法及時完成那些複雜的介面渲染操作。
Android系統每隔16ms發出VSYNC訊號,觸發對UI進行渲染,如果每次渲染都成功,
這樣就能夠達到流暢的畫面所需要的60fps,為了能夠實現60fps,
這意味著程式的大多數操作都必須在16ms內完成。
如果你的某個操作花費時間是24ms,系統在得到VSYNC訊號的時候就無法進行正常渲染,
這樣就發生了丟幀現象。那麼使用者在32ms內看到的會是同一幀畫面。
使用者容易在UI執行動畫或者滑動ListView的時候感知到卡頓不流暢,
是因為這裡的操作相對複雜,容易發生丟幀的現象,從而感覺卡頓。
有很多原因可以導致丟幀,也許是因為你的layout太過複雜,無法在16ms內完成渲染,
有可能是因為你的UI上有層疊太多的繪製單元,還有可能是因為動畫執行的次數過多。這些都會導致CPU或者GPU負載過重。
總結:盡量避免寫過於複雜的layout,布局盡量簡單明了,在寫布局的時候一定要考慮效能問題,避免嵌套 重複 冗餘。
2 、overdraw(過度繪製)描述的是螢幕上的某個像素在同一幀的時間內被繪製了多次。
在多層次的UI結構裡面,如果不可見的UI也在做繪製的操作,這就會導致某些像素地區被繪製了多次。
這就浪費大量的CPU以及GPU資源。
當設計上追求更華麗的視覺效果的時候,我們就容易陷入採用越來越多的層疊組件來實現這種視覺效果的怪圈。
這很容易導致大量的效能問題,為了獲得最佳的效能,我們必須盡量減少Overdraw的情況發生。
Overdraw有時候是因為你的UI布局存在大量重疊的部分,還有的時候是因為非必須的重疊背景。
例如某個Activity有一個背景,然后里面的Layout又有自己的背景,同時子View又分別有自己的背景。
僅僅是通過移除非必須的背景圖片,這就能夠減少大量的紅色Overdraw地區,增加藍色地區的佔比。
這一措施能夠顯著提升程式效能。
總結:要避免布局重複的繪製,如果不是特別需要盡量避免多個view使用重複或不同的背景
3、雖然Android有自動管理記憶體的機制,但是對記憶體的不恰當使用仍然容易引起嚴重的效能問題。
在同一幀裡面建立過多的對象是件需要特別引起注意的事情。
Android系統裡面有一個Generational Heap Memory的模型,
系統會根據記憶體中不同的記憶體資料類型分別執行不同的GC操作。
例如,最近剛分配的對象會放在Young Generation地區,
這個地區的對象通常都是會快速被建立並且很快被銷毀回收的,
同時這個地區的GC操作速度也是比Old Generation地區的GC操作速度更快的。
除了速度差異之外,執行GC操作的時候,任何線程的任何操作都會需要暫停,等待GC操作完成之後,其他動作才能夠繼續運行。
通常來說,單個的GC並不會佔用太多時間,但是大量不停的GC操作則會顯著佔用幀間隔時間(16ms)。
如果在幀間隔時間裡面做了過多的GC操作,那麼自然其他類似計算,渲染等操作的可用時間就變得少了。
導致GC頻繁執行有兩個原因:
1、Memory Churn記憶體抖動,記憶體抖動是因為大量的對象被建立又在短時間內馬上被釋放。
2、瞬間產生大量的對象會嚴重佔用Young Generation的記憶體地區,當達到閥值,剩餘空間不夠的時候,
也會觸發GC。即使每次分配的對象佔用了很少的記憶體,但是他們疊加在一起會增加Heap的壓力,
從而觸發更多其他類型的GC。這個操作有可能會影響到幀率,並使得使用者感知到效能問題。
總結:你需要避免在for迴圈裡面指派至佔用記憶體,需要嘗試把對象的建立移到迴圈體之外,
自訂View中的onDraw方法也需要引起注意,每次螢幕發生繪製以及動畫執行過程中,
onDraw方法都會被調用到,避免在onDraw方法裡面執行複雜的操作,避免建立對象。
對於那些無法避免需要建立對象的情況,我們可以考慮對象池模型,通過對象池來解決頻繁建立與銷毀的問題,
但是這裡需要注意結束使用之後,需要手動釋放對象池中的對象。
4、雖然Java有自動回收的機制,可是這不意味著Java中不存在記憶體流失的問題,而記憶體流失會很容易導致嚴重的效能問題。
記憶體流失指的是那些程式不再使用的對象無法被GC識別,這樣就導致這個對象一直留在記憶體當中,
佔用了寶貴的記憶體空間。顯然,這還使得每級Generation的記憶體地區可用空間變小,GC就會更容易被觸發,從而引起效能問題。
5 、電量其實是目前手持功能最寶貴的資源之一,大多數裝置都需要不斷的充電來維持繼續使用。
不幸的是,對於開發人員來說,電量最佳化是他們最後才會考慮的的事情。但是可以確定的是,千萬不能讓你的應用成為消耗電量的大戶。
Purdue University研究了最受歡迎的一些應用的電量消耗,
平均只有30%左右的電量是被程式最核心的方法例如繪製圖片,擺放布局等等所使用掉的,
剩下的70%左右的電量是被上報資料,檢查位置資訊,定時檢索後台廣告資訊所使用掉的。
如何平衡這兩者的電量消耗,就顯得非常重要了。
有下面一些措施能夠顯著減少電量的消耗:
1、我們應該盡量減少喚醒螢幕的次數與持續的時間,使用WakeLock來處理喚醒的問題,
能夠正確執行喚醒操作並根據設定及時關閉操作進入睡眠狀態。
2、某些非必須馬上執行的操作,例如上傳歌曲,圖片處理等,可以等到裝置處於充電狀態或者電量充足的時候才進行。
3、 觸發網路請求的操作,每次都會保持無線訊號持續一段時間,我們可以把零散的網路請求打包進行一次操作,
避免過多的無線訊號引起的電量消耗。關於網路請求引起無線訊號的電量消耗
Android效能最佳化(一)