編輯:關於Android編程
在前兩篇文章當中,我們主要學習了Android內存方面的相關知識,包括如何合理地使用內存,以及當發生內存洩露時如何定位出問題的原因。那麼關於內存的知識就討論到這裡,今天開始我們將學習一些性能編碼優化的技巧。
這裡先事先提醒大家一句,本篇文章中討論的編碼優化技巧都是屬於一些“微優化”,也就是說即使我們都按照本篇文章的技巧來優化代碼,在性能方面也是看不出有什麼顯著的提升的。使用合適的算法與數據結構將永遠是你優化程序性能的最主要手段,但本篇文章中不會討論這一塊的內容。因此,這裡我們即將學習的並不是什麼靈丹妙藥,而是大家應該把這些技巧當作一種好的編碼規范,我們在平時寫代碼時就可以潛移默化地使用這些編碼規范,不僅能夠在微觀層面提升程序一定的性能,也可以讓我們的代碼變得更加專業,下面就讓我們來一起學習一下這些技巧。
創建對象從來都不應該是一件隨意的事情,因為創建一個對象就意味著垃圾回收器需要回收一個對象,而這兩步操作都是需要消耗時間的。雖說創建一個對象的代價確實非常小,並且Android 2.3版本當中又增加了並發垃圾回收器機制(詳見Android最佳性能實踐(二)——分析內存的使用情況),這讓GC操作時的停頓時間也變得難以察覺,但是這些理由都不足以讓我們可以肆意地創建對象,需要創建的對象我們自然要創建,但是不必要的對象我們就應該盡量避免創建。
下面來看一些我們可以避免創建對象的場景:
如果我們有一個需要拼接的字符串,那麼可以優先考慮使用StringBuffer或者StringBuilder來進行拼接,而不是加號連接符,因為使用加號連接符會創建多余的對象,拼接的字符串越長,加號連接符的性能越低。在沒有特殊原因的情況下,盡量使用基本數據類來代替封裝數據類型,int比Integer要更加高效,其它數據類型也是一樣。當一個方法的返回值是String的時候,通常可以去判斷一下這個String的作用是什麼,如果我們明確地知道調用方會將這個返回的String再進行拼接操作的話,可以考慮返回一個StringBuffer對象來代替,因為這樣可以將一個對象的引用進行返回,而返回String的話就是創建了一個短生命周期的臨時對象。正如前面所說,基本數據類型要優於對象數據類型,類似地,基本數據類型的數組也要優於對象數據類型的數組。另外,兩個平行的數組要比一個封裝好的對象數組更加高效,舉個例子,Foo[]和Bar[]這樣的兩個數組,使用起來要比Custom(Foo,Bar)[]這樣的一個數組高效得多。當然上面所說的只是一些代表性的例子,我們所要遵守的一個基本原則就是盡可能地少創建臨時對象,越少的對象意味著越少的GC操作,同時也就意味著越好的程序性能和用戶體驗。
如果你並不需要訪問一個對象中的某些字段,只是想調用它的某個方法來去完成一項通用的功能,那麼可以將這個方法設置成靜態方法,這會讓調用的速度提升15%-20%,同時也不用為了調用這個方法而去專門創建對象了,這樣還滿足了上面的一條原則。另外這也是一種好的編程習慣,因為我們可以放心地調用靜態方法,而不用擔心調用這個方法後是否會改變對象的狀態(靜態方法內無法訪問非靜態字段)。
我們先來看一下在一個類的最頂部定義如下代碼:
[java]view plaincopy
但是我們還可以通過final關鍵字來對上述代碼進行優化:
[java]view plaincopy
另外需要大家注意的是,這種優化方式只對基本數據類型以及String類型的常量有效,對於其它數據類型的常量是無效的。不過,對於任何常量都是用static final的關鍵字來進行聲明仍然是一種非常好的習慣。
增強型for循環(也被稱為for-each循環)可以用於去遍歷實現Iterable接口的集合以及數組,這是jdk 1.5中新增的一種循環模式。當然除了這種新增的循環模式之外,我們仍然還可以使用原有的普通循環模式,只不過它們之間是有效率區別的,我們來看下面一段代碼:
[java]view plaincopy
但是這裡要跟大家提一個特殊情況,對於ArrayList這種集合,自己手寫的循環要比增強型for循環更快,而其他的集合就沒有這種情況。因此,對於我們來說,默認情況下可以都使用增強型for循環,而遍歷ArrayList時就還是使用傳統的循環方式吧。
Java語言當中其實給我們提供了非常豐富的API接口,我們在編寫程序時如果可以使用系統提供的API就應該盡量使用,系統提供的API完成不了我們需要的功能時才應該自己去寫,因為使用系統的API在很多時候比我們自己寫的代碼要快得多,它們的很多功能都是通過底層的匯編模式執行的。
比如說String類當中提供的好多API都是擁有極高的效率的,像indexOf()方法和一些其它相關的API,雖說我們通過自己編寫算法也能夠完成同樣的功能,但是效率方面會和這些方法差的比較遠。這裡舉個例子,如果我們要實現一個數組拷貝的功能,使用循環的方式來對數組中的每一個元素一一進行賦值當然是可行的,但是如果我們直接使用系統中提供的System.arraycopy()方法將會讓執行效率快9倍以上。
我們平時寫代碼時都被告知,一定要使用面向對象的思維去寫代碼,而面向對象的三大特性我們都知道,封裝、多態和繼承。其中封裝的基本思想就是不要把類內部的字段暴漏給外部,而是提供特定的方法來允許外部操作相應類的內部字段,從而在Java語言當中就出現了Getters/Setters這種封裝技巧。
然而在Android上這個技巧就不再是那麼的受推崇了,因為字段搜尋要比方法調用效率高得多,我們直接訪問某個字段可能要比通過getters方法來去訪問這個字段快3到7倍。不過我們肯定不能僅僅因為效率的原因就將封裝這個技巧給拋棄了,編寫代碼還是要按照面向對象思維的,但是我們可以在能優化的地方進行優化,比如說避免在內部調用getters/setters方法。
那什麼叫做在內部調用getters/setters方法呢?這裡我舉一個非常簡單的例子:
[java]view plaincopy
這裡我們注意到,getSum()方法當中的算法就是將one和two的值相加進行返回,但是它獲取one和two的值的方式也是通過getters方法進行獲取的,其實這是一種完全沒有必要的方式,因為getSum()方法本身就是Calculate類內部的方法,它是可以直接訪問到Calculate類中的封裝字段的,因此這種寫法在Android上是不推崇的,我們可以進行如下修改:
[java]view plaincopy當然,本篇文章中推薦的這些技巧呢也並不全面,只是從Android官方文檔抽取了幾個感覺比較實用的分享給大家,更多技巧大家也可以到Android官網上去閱讀。另外在高性能編碼方面《Efficient Java》這本書當中也提供了非常多的技巧,有興趣的朋友也可以去閱讀一下這本書。那麼本篇文章就到這裡。
實現效果: 因為業務需要,以下代碼均以Youtube網站在線視頻為例 實現功能: 1、初始化的時候顯示標題和視頻封面 2、初始化的時候顯示一個play按鈕 3、不需
當你的應用需要顯示一個進度條或需要用戶對信息進行確認時,可以使用alertDialog來完成。下面來介紹常用的四種AlertDialog。1、普通對話框package c
本文目標實現控制小飛機的左右移動、躲避子彈、打boss。本節實現 開始菜單界面1、首先 資源文件拷過來2、劃分游戲狀態 public static final int G
Tab標簽頁是一個非常常用的控件,.net裡面就有multipage+tabstrip組合通過標簽的切換實現頁面的切換,同理html裡面我們常用frameset來