標籤:源檔案 系統 細節 複製粘貼 根據 延長 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 不要直接使用 +號 進行字串拼接
開發中使用“+”號運算子的確非常方便,但是效率也非常低,因為“+”號內部實際上調用的是StringBuffer的append()方法,然後再轉換成String,那麼它肯定沒有直接調用快。
還有一個就是StringBuilder,這個類是Java1.5時出來的,從效率上來說,它和StringBuffer區別在於StringBuilder不是安全執行緒的,多線程操作會出現問題,那麼就比較容易選擇了,
在單線程中,使用StringBuilder,在多線程中使用StringBuffer
1.2 不要直接使用 +“” 來進行字串轉化
將對象轉化成字串的操作有三種,效率從快到慢依次是,xxx.toString、String.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的提示,
使用SparseArray比HashMap好,所以就網上尋找了些SparseArray的一些相關資料
簡單的來講,SparseArray適用於HashMap<Integer, Object>這樣的結構,因為SparseArray內部是用的int型數組儲存key和Object型的數組儲存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會使對象無法被繼承,變數無法被修改,方法無法被重寫,並且會進行內聯
結束
暫時想到的就這麼多了,僅僅是一些開發中的細節部分,有些眾所周知的就沒寫,比如複用ListView的ConvertView,壓縮圖片、非同步載入等等,
Android開發中的效能最佳化---代碼