Jen

Android App開發效能你知多少?

(以下為個人心得,部分並無實作過)

 

首先要說的就是GC(Garbage Collection),越頻繁的GC對於app的performance當然是越有影響,所以在coding方面就是要盡量減少GC的發生。

 

最基本的就是StringBuilder的應用時機,及String Pool的觀念,這應該是人人都知道吧。

像android裏面有個Handler(android.os) 類別,常用在main-Thread去偵聽child-Thread所產生的訊息。如果要傳空白字串的話,有個sendEmptyMessage()方法,總聽到有人說這個方法比起sendMessage(Message)效能來得好,原因就是sendEmptyMessage()是send一個被編譯在dex file裏的value,並不會產生一個String的實體到String pool去,一來節省記憶體,二來減少GC事件的發生。(以上是我個人的假設及猜測。)

 

盡量避免產生新的實體。

例如:

如果你要在傳入的String中擷取某些String,盡量從原本傳入的String來subString(),不要再另外複製一份。

    public String get50Str(String data){
        return (data.length() > 50)? data.substring(0,50):data;
    }

 

舉個例子,假設你有一個回傳String的函式,且回傳的值是一定被append到StringBuffer的話,就不要return來建立多餘的short-lived temporary object,直接傳StringBuffer 的 reference在函式裏面動作即可。

    public void append(StringBuffer sb,String apStr){
            sb.append(apStr);
    }

用int的陣列會來的比用Integer的陣列好(同float及Float)。

因為int 是primitive type, Integer 是類別。之前有聽到人家問說為什麼int沒有方法,而Integer有方法好奇怪,而且只有int會這樣。其實我想說,不只是int這樣,要搞清楚什麼是java的primitive type,int 之於 Integer 、float之於Float…還有關於autoboxing、unboxing的觀念。

總之,物件實例越少,就會越少的GC,而越少的GC,效能就會更好。

 

Getters 及 Setters的使用

getField()及setField(value)是我一般寫Java的習慣用法,我想大家都一樣,但android文件明確指明 this is Bad Idea,直接public 該field 會比較快(我也不知道為什麼,一定又是編譯器對這方面優化做的還不夠。)

public class foo

{

    private String _name;

    public getName() { return _name; }

    public setName(String value) { _name = value; }

}

如果突然要加一些設定值的限制或取值的設定,這樣的寫法是方便,但為什麼是個Bad Idea呢 ?

 

 

用static final來宣告常數

  static int intVal = 100; (不好)

  static final int intVal = 100; (好)

編譯器會產生一個類別初始化方法,叫 clinit,當這個class第一次被使用的時候就會呼叫這個方法,然後把100丟到intVal這個field。如果加上final, 這個intVal就會直接被compiler到dex file,並不需要clinit這個方法。

 

 

迴圈

class Shit { }

Shit[] mShits = new Shit[n];

for (Shit s : mShits) { }

對於編譯器來說,這是優化過的迴圈寫法,可以多多利用喔。

 

避免使用Enums。

Enums是很方便,但是對於記憶體及速度都有一定的影響,特別又是在手機這種硬體資源有限的情況下,這個部分需要多多考慮,特別你只是要一個數字的對應。

 

 

關於Thread的議題

Main-Thread(aka UI-Thread)不能被block 超過5秒這也是大家都知道的,所以有可能會發生長時間工作的事件都要在Child-Thread來完成,然後在Main-Thread做一個handler或 listener來偵聽結果。像Network Operation、Database Operation、Bitmap的resizing…etc.

 

最近我就在寫一些 Web Service Calling API,把Web Service的一些動作、資訊(Server Uri、request Uri…etc)寫在一個類別,再另外寫一個 Async 非同步處理的類別,專門產生child-Thread 來做Web Service Call的動作,自訂一個Listener(也可以用Handler,資訊就用Message互丟)來偵聽child-Thread 完成的結果。需要注意的是,如果是自訂 Listener ,必須注意下面這段Code

12334

如果有一些關於UI的動作,就要透過 runOnUiThread() 把要更新UI的動作加到main Thread的排程裏面去。Thread是OS 的基本觀念之一,沒吃過也要看過(你必須要知道:Thread(computer science) ).

 

順帶一提的是,在API Level 9 (Gingerbread),android 提供了StrictMode 這個tools 讓你去 log 在你做這些長時間的operation 的時候發生的一些意外。不過我還沒用過,我目前也都在2.1練習一下小兒科得東西。

 

(持續新增…)

 

JVM (android裏就是Dalvik - DVM) 的相關知識還是要多看一些,真的不要只是看看範例,複製貼上而以。

 

參考:

Effective Java (中譯本)

Android Developers : Dev Guide

Dalvik 記憶體管理

0 意見: