Android效能優化之運算篇

胡凱發表於2015-09-16

運算篇

1) Intro to Compute and Memory Problems

Android中的Java程式碼會需要經過編譯優化再執行的過程。程式碼的不同寫法會影響到Java編譯器的優化效率。例如for迴圈的不同寫法就會對編譯器優化這段程式碼產生不同的效率,當程式中包含大量這種可優化的程式碼的時候,運算效能就會出現問題。想要知道如何優化程式碼的運算效能就需要知道程式碼在硬體層的執行差異。

2) Slow Function Performance

如果你寫了一段程式碼,它的執行效率比想象中的要差很多。我們需要知道有哪些因素有可能影響到這段程式碼的執行效率。例如:比較兩個float數值大小的執行時間是int數值的4倍左右。這是因為CPU的運算架構導致的,如下圖所示:

雖然現代的CPU架構得到了很大的提升,也許並不存在上面所示的那麼大的差異,但是這個例子說明了程式碼寫法上的差異會對運算效能產生很大的影響。

通常來說有兩類執行效率差的情況:第1種是相對執行時間長的方法,我們可以很輕鬆的找到這些方法並做一定的優化。第2種是執行時間短,但是執行頻次很高的方法,因為執行次數多,累積效應下就會對效能產生很大的影響。

修復這些細節效率問題,需要使用Android SDK提供的工具,進行仔細的測量,然後再進行微調修復。

3) Traceview Walkthrough

通過Android Studio開啟裡面的Android Device Monitor,切換到DDMS視窗,點選左邊欄上面想要跟蹤的程式,再點選上面的Start Method Tracing的按鈕,如下圖所示:

啟動跟蹤之後,再操控app,做一些你想要跟蹤的事件,例如滑動listview,點選某些檢視進入另外一個頁面等等。操作完之後,回到Android Device Monitor,再次點選Method Tracing的按鈕停止跟蹤。此時工具會為剛才的操作生成TraceView的詳細檢視。

關於TraceView中詳細資料如何檢視,這裡不展開了,有很多文章介紹過。

4) Batching and Caching

為了提升運算效能,這裡介紹2個非常重要的技術,Batching與Caching。

Batching是在真正執行運算操作之前對資料進行批量預處理,例如你需要有這樣一個方法,它的作用是查詢某個值是否存在與於一堆資料中。假設一個前提,我們會先對資料做排序,然後使用二分查詢法來判斷值是否存在。我們先看第一種情況,下圖中存在著多次重複的排序操作。

在上面的那種寫法下,如果資料的量級並不大的話,應該還可以接受,可是如果資料集非常大,就會有嚴重的效率問題。那麼我們看下改進的寫法,把排序的操作打包繫結只執行一次:

上面就是Batching的一種示例:把重複的操作拎出來,打包只執行一次。

Caching的理念很容易理解,在很多方面都有體現,下面舉一個for迴圈的例子:

上面這2種基礎技巧非常實用,積極恰當的使用能夠顯著提升運算效能。

5) Blocking the UI Thread

提升程式碼的運算效率是改善效能的一方面,讓程式碼執行在哪個執行緒也同樣很重要。我們都知道Android的Main Thread也是UI Thread,它需要承擔使用者的觸控事件的反饋,介面檢視的渲染等操作。這就意味著,我們不能在Main Thread裡面做任何非輕量級的操作,類似I/O操作會花費大量時間,這很有可能會導致介面渲染髮生丟幀的現象,甚至有可能導致ANR。防止這些問題的解決辦法就是把那些可能有效能問題的程式碼移到非UI執行緒進行操作。

6) Container Performance

另外一個我們需要注意的運算效能問題是基礎演算法的合理選擇,例如氣泡排序與快速排序的效能差異:

避免我們重複造輪子,Java提供了很多現成的容器,例如Vector,ArrayList,LinkedList,HashMap等等,在Android裡面還有新增加的SparseArray等,我們需要了解這些基礎容器的效能差異以及適用場景。這樣才能夠選擇合適的容器,達到最佳的效能。

相關文章