1、如果需要用很多個物件時可以使用Cache,經常寫Java的人可能會使用HashMap去實現Cache,但當Key是Integer的值時,Android為我們定義了一個更有效率的一個類:SparseArray類,它具有比HashMap更高的效率。
2、不同的API版本針對不同的功能已經做了最佳化,有些函數被棄用,啟用新的調用函數,因此,在實現不同的API版本的時候,可針對不同的API進行不同程度的最佳化,個人覺得這種最佳化成本高,收益小。如:在HONEYCOMB中,sparseArray進行了最佳化,因此在使用高版本的sdk時,使用新的函數,對於低版本使用舊的相容函數實現。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {sparseArray.removeAt(1); // API level 11 and above} else {int key = sparseArray.keyAt(1); // 預設實現效率更低sparseArray.remove(key);}
3、效能並不僅僅指程式的執行速度,也包括使用者互動體驗,使用者在使用軟體時的響應速度等。ui線程用來處理按鍵訊息(如:View.onKeyDown()或Activity.onKeyLongPress()),圖形繪畫(如:View.onDraw())以及生命週期時間的發生(如:onCreate(),onStart()等),其它不重要的代碼盡量放到非ui線程去處理,避免出現ANR(Application
Not Responding)的出現。
在Activity中,盡量減少Activity的啟動時間是非常重要的,盡量減小在onCreate(),onStart(),onResume()中執行過於耗時的操作,如,Activeity的onCreate()方法中一般使用setContentView或者其它的方式去添加視圖inflate視圖,而inflate視圖的過程是比較耗時的,因此UI介面的設計非常重要,在xml中,盡量使用簡潔的布局可以減少布局的載入時間,有一些常用的操作,比如:
(1)使用RelativeLayout代替LinearLayout
(2)view的layout盡量使用viewroot去實現消極式載入,加快ui展示
具體詳看我之前的文章:Tips from Android SDK Articles
4、在針對網路和檔案操作時應處理低網速及io操作的情況,sd卡有不同的處理速度,如果我們的程式很依賴於sd卡的效能,那就必須重點測試下不同廠家的sd卡
5、在2.3後可以使用StrictMode去輔助測試程式在低速率下或者其它情況下的使用者體驗和程式的健壯性,注意,這個僅在開發時使用,發布版本時必須去掉。舉個例子如下:讓你的代碼執行的效率低點:
public static BigInteger computeRecursivelyWithCache(int n){StrictMode.noteSlowCall(“computeRecursivelyWithCache”); // message can beanythingSparseArray<BigInteger> cache = new SparseArray<BigInteger>();return computeRecursivelyWithCache(n, cache);}…}
6、資料庫最佳化
我們在使用資料庫的時候,經常會使用到CREATE TABLE, INSERT INTO語句等,舉個例子:
SQLiteDatabase db = SQLiteDatabase.create(null); db.execSQL(“CREATE TABLE cheese (name TEXT, origin TEXT)”);db.execSQL(“INSERT INTO cheese VALUES (‘Roquefort’, ‘Roquefort-sur-Soulzon’)”);db.close();
執行SQLite語句的時候會花一定的時間,這些語句需要:解釋或者編譯或者執行而且而且String是不可變的,因此在構成該語句的時候,又進行了很多個物件的建立操作,導致效能的問題。這裡通過舉個例子去詳細講解下:
public class Cheeses {private static final String[] sCheeseNames = {“Abbaye de Belloc”,“Abbaye du Mont des Cats”,…“Vieux Boulogne”};private static final String[] sCheeseOrigins = {“Notre-Dame de Belloc”,“Mont des Cats”,…“Boulogne-sur-Mer”};private final SQLiteDatabase db;public Cheeses () {db = SQLiteDatabase.create(null); // memory-backed databasedb.execSQL(“CREATE TABLE cheese (name TEXT, origin TEXT)”);}public void populateWithStringPlus () {int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];String sql = “INSERT INTO cheese VALUES(\”” + name + ”\”,\”” + origin +”\”)”;db.execSQL(sql);}}}
在執行populateWithStringPlus的時候,會建立大量的String對象以及執行execSQL。針對第一點,最明顯的最佳化的手段就是少用String的+操作,使用String.format或者StringBuilder進行代替:
public void populateWithStringFormat () {int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];CHAPTER 1: Optimizing Java Code 27String sql = String.format(“INSERT INTO cheese VALUES(\”%s\”,\”%s\”)”, name,origin);db.execSQL(sql);}}public void populateWithStringBuilder () {StringBuilder builder = new StringBuilder();builder.append(“INSERT INTO cheese VALUES(\””);int resetLength = builder.length();int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];builder.setLength(resetLength); // reset positionbuilder.append(name).append(“\”,\””).append(origin).append(“\”)”); // chaincallsdb.execSQL(builder.toString());}}
當添加愛650條資料時,String.format花436ms的時候,而StringBuilder花了371ms,後者效率更佳,但不是很明顯。
最佳化的第二個方法:因為每條插入語句都差不多,只不過資料有變化而已,因此可以使用compileStatement建立語句進行複用,在迴圈外僅編譯一次語句:
public void populateWithCompileStatement () {SQLiteStatement stmt = db.compileStatement(“INSERT INTO cheese VALUES(?,?)”);int i = 0;for (String name : sCheeseNames) {String origin = sCheeseOrigins[i++];stmt.clearBindings();stmt.bindString(1, name); // replace first question mark with namestmt. bindString(2, origin); // replace second question mark with originstmt.executeInsert();}}
在該方法中,SQL語句僅編譯一次,而無需編譯650次,最佳化後的時間僅僅268ms
8、讀取資料庫時盡量只選取所需要的資料去讀,不要全部都讀
public void iterateBothColumns () {Cursor c = db.query(“cheese”, null, null, null, null, null, null);if (c.moveToFirst()) {do {} while (c.moveToNext());}c.close(); }public void iterateFirstColumn () {Cursor c = db.query(“cheese”, new String[]{“name”}, null, null, null, null, null); // 不一樣的地方if (c.moveToFirst()) {do {} while (c.moveToNext());}c.close();}
如第一個方法讀取所有資料,而第二個方法讀取name的資料,後者的所花的時間比前者少。