Android開發中的效能最佳化---代碼

來源:互聯網
上載者:User

標籤:源檔案   系統   細節   複製粘貼   根據   延長   ali   limit   可讀性   

  這篇主要總結一些最佳化代碼的技巧,一些寫代碼中的小細節,可能就會影響程式的執行效率,比如一個地方只會影響1ms,那麼1000個地方就會影響1s,1s到底長不長?要知道Activity出現ANR異常的時間為5s!!! 
  主要遵循兩個原則 
  1.不要建立一些沒必要建立的對象以及重複定義某個變數 
  對象的建立是一個非常繁瑣的步驟,JVM首先會對通過new指令對符號進行解析,以此來判斷該類是否被載入,然後在堆中進行記憶體配置,為對象分配完記憶體空間後,就會對記憶體地區進行初始化(該為0的為0,該為null的為null,這也是為什麼方法中的變數需要程式員顯示初始化),最後JVM會調用對象的建構函式,而且一般都會有一個變數建立該對象的引用。 
  所以,建立對象是很麻煩的,就不要沒事幹就建立對象了。 
   
  2.用完的對象要及時回收 
  就是常說的GC,這裡要明確的是,什麼時候進行GC操作,不是由程式員決定的,JVM會在有必要的時候自行啟動GC,程式員只能做到建議JVM儘快對某對象進行GC,它有兩個評判標準 
  (1) 該對象失去引用,那麼最好的辦法就是將不用的對象賦值為null 
  (2) 該對象離開範圍,比如說方法執行完畢,局部變數和對象就會被回收,所以儘可能少生命全域變數。 
  並且GC操作也是要耗記憶體的@[email protected]! 
  

開始1.最頻繁的 + 和 +“” 操作

  Java中的 +號既可以進行數值計算,又可以進行字串操作,但是在進行字串操作的時候,它是一種效率很低的方式,雖然用起來非常非常方便!

1.1 不要直接使用 +號 進行字串拼接

  開發中使用“+”號運算子的確非常方便,但是效率也非常低,因為“+”號內部實際上調用的是StringBufferappend()方法,然後再轉換成String,那麼它肯定沒有直接調用快。 
  還有一個就是StringBuilder,這個類是Java1.5時出來的,從效率上來說,它和StringBuffer區別在於StringBuilder不是安全執行緒的,多線程操作會出現問題,那麼就比較容易選擇了, 
  在單線程中,使用StringBuilder,在多線程中使用StringBuffer

 

1.2 不要直接使用 +“” 來進行字串轉化

  將對象轉化成字串的操作有三種,效率從快到慢依次是,xxx.toStringString.valueOf(xxx)、 xxx +"" 
  xxx.toString是直接轉化,而String.valueOf(xxx)底層是調用了toString()方法,至於+"",在1.1時已經說了,它會先轉化成SringBuffer,然後再調用toString(),所以結果一目瞭然

 

上述兩點可以看下面的代碼

 通過javap -c 的指令, 能夠看到下面的內容, 雖然左邊的不一定能看懂, 但是右邊的注釋很容易理解 

 

2.迴圈的使用細節(以for為例)

  迴圈是開發中頻率出現很高的一種操作,它的作用就是簡化重複的步驟,比如說添加10000條資料到某個集合中,如果不用迴圈,即使複製粘貼也要好久,但是通過迴圈操作就可以幾行程式碼完成。但這裡面就會容易出現一些小的細節,有可能就會影響程式的執行效率。以下代碼舉例:

1 List<String> list = new ArrayList<>();2 for (int i = 0; i < 100; i++) {3     Random random = new Random();4     Integer result = random.nextInt(100);5     String s = result.toString();6     list.add(s);7 }    

 

2.1 盡量不要在迴圈中建立不必要的對象

  範例程式碼中在for迴圈中建立了100個Random對象,而實際進行隨機數操作的是該對象的nextInt()方法,那麼實際上可以寫成:

  

List<String> list = new ArrayList<>();// 對象建立在for迴圈外Random random = new Random();for (int i = 0; i < 100; i++) {    Integer result = random.nextInt(100);    String s = result.toString();    list.add(s);}

 

2.2 不用的對象要及時回收


  這裡只是舉個例子,實際開發中有可能出現的情況是,解析一段Json,然後擷取到了Json中的某個對象並添加到了集合中,那麼這個被解析過的對象其實就沒什麼用了,因為資料已經添加到了集合中,比較我們要用的是資料而不是對象,此時就可以置為null,讓JVM儘快的回收掉它,這是一個非常好的習慣,

  但有些時候例外, 面這種情況, 將對象置為null, 但實際上該對象的引用仍然被list集合所持有, 所以對象不會被回收掉

  

 1 List<String> list = new ArrayList<>(); 2 Random random = new Random(); 3 Integer result; 4 String s; 5 for (int i = 0; i < 100; i++) { 6     result = random.nextInt(100); 7     s = result.toString(); 8     list.add(s); 9     result = null;  // 此時雖然將對象置為null, 但是它的引用依然是被list所持有的, 即使result置為null, 仍然不會來回收10     s = null;11 }

 

  比較好的做法應該是清空list集合然後將list置為null

1 list.clear();  // 要先將list所持有的對象給清空掉2 if(list != null) {3     list = null;4 }

在實際開發中, 可以寫在onDestory()方法中

 

2.4 適當的建立方法結果的緩衝

  比如有時候為了簡便會這樣寫 
   
   
   
  Java在調用某個方法時,其實也不是那麼簡單,要建立棧幀來儲存局部變數表,運算元棧,動態串連,方法返回地址,還要方法調用現場、恢複方法調用現場等一系列操作。所以,如果list的size()非常大時,也會影響效率,所以可以定義一個變數而不是直接使用 
   
  

 

3. if和switch的使用

  既然有了迴圈,那麼就應當有判斷@[email protected]!

3.1 通過if來在合適的時候建立對象或調用方法

  這個也算一個小細節 
   
   
  這個迴圈裡面可以看出,只有在隨機數為20的時候集合才會添加該資料,所以在此之前,將隨機數調用toString()方法毫無意義。所以可以寫為 
  

 4 使用位元運算來代替乘除運算

  電腦只懂二進位,而位元運算就是直接的二進位運算,所以當然效率比較高,

  當然也有缺點 
    (1) 對於數字過大,還是直接乘除比較方便 
    (2) 代碼的可讀性不高

 5 合理利用Activity的生命週期

  Activity的生命週期最常用的莫過於onCreate(),但是其它的生命週期我想也很有必要恰當的利用。 
   
   
  這個僅僅是個人書寫習慣,不知道會不會影響到效能,但是最起碼這樣寫代碼結構比較清晰 :)

 6 使用Zipalign來進行代碼對齊

  Zipalign是一個SDK下的工具,能夠對apk檔案中未壓縮的資料在4個位元組邊界上對齊,當資源檔通過記憶體映射對齊到4位元組邊界時,android系統就可以通過調用mmap函數讀取檔案, 
  mmap函數是Linux系統的調用函數,提供了不同於一般對普通檔案的訪問方式,進程可以像讀寫記憶體一樣對普通檔案的操作,進程可以像讀寫記憶體一樣對普通檔案的操作,不必再read()和write(),在讀取資源上獲得較高的效能。如果資源本身沒有進行對齊處理,它就必須顯式地讀取它們——這個過程將會比較緩慢且會花費額外的記憶體。 
  具體用法我會在工具篇中總結

 7 使用SparseArray代替HashMap  使用 SparseArray來代替 HashMap,原因是一次Android Studio的提示, 

   
   
  使用SparseArrayHashMap好,所以就網上尋找了些SparseArray的一些相關資料 
  簡單的來講,SparseArray適用於HashMap<Integer, Object>這樣的結構,因為SparseArray內部是用的int型數組儲存keyObject型的數組儲存value的值,省去了int封裝成Integer的過程. 
   
   
  根據這篇文章,可以看出來,在資料過多時,效率上SparseArray並沒有比HashMap更快,但是該文章作者結尾處說記憶體的使用狀況上,能夠節約27% 
  
   
  而這篇文章的作者專門對記憶體的使用狀況做了測試,說是記憶體上最佳化了35% 
   
  
  我通過Android Studio內建的工具觀察記憶體消耗,使用HashMap大約在3.24~3.31 
   
  
  而SparseArray大約在3.0~3.1之間 
   
  
    不過具體最佳化了多少不是重點,反正是對記憶體開銷上SparseArray開銷更低更具有優勢~! 
 另外除了SparseArray,ArrayMap,SparseBoolMap,SparseIntMap,SparseLongMap,LongSparseMap等等一些列API,在記憶體使用量方面都相對於HashMap要好的多

 8 I/O流盡量使用帶Buffer的

  帶Buffer緩衝區的I/O對象效率要比不帶的高一些,

9. 能不static就不static,能final就final

  static雖然讓成員用起來很爽,但是會延長它們的生命週期 
  final會使對象無法被繼承,變數無法被修改,方法無法被重寫,並且會進行內聯

結束

  暫時想到的就這麼多了,僅僅是一些開發中的細節部分,有些眾所周知的就沒寫,比如複用ListViewConvertView,壓縮圖片、非同步載入等等,

Android開發中的效能最佳化---代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.