20條App性能優(yōu)化的建議
你的app為什么會卡?為什么占用大內(nèi)存?應(yīng)該怎么解決?這篇文章會給你答案。
20條建議
1. itmap的合理使用:使用Bitmap過后,就需要及時的調(diào)用recycle()方法來釋放Bitmap占用的內(nèi)存空間,而不要等Android系統(tǒng)來進行釋放。
代碼示例:
//?先判斷是否已經(jīng)回收
if(bitmap?!=?null?&&?!bitmap.isRecycled()){
bitmap.recycle();
bitmap?=?null;
}
System.gc();
2. 對常量使用static final修飾符
static final?int intVal = 42;
static final?String strVal = “Hello, world!”;
將一個方法或類聲明為final不會帶來性能的提升,但是會幫助編譯器優(yōu)化代碼。舉例說,如果編譯器知道一個getter方法不會被重載,那么編譯器會對其采用內(nèi)聯(lián)調(diào)用。
3. 靜態(tài)方法代替虛擬方法
如果不需要訪問某對象的字段,將方法設(shè)置為靜態(tài),調(diào)用會加速15%到20%。這也是一種好的做法,因為你可以從方法聲明中看出調(diào)用該方法不需要更新此對象的狀態(tài)。
4. 減少不必要的全局變量
盡量避免static成員變量引用資源耗費過多的實例,比如Context,因為Context的引用超過它本身的生命周期,會導(dǎo)致Context泄漏。所以盡量使用Application這種Context類型。?可以通過調(diào)用Context.getApplicationContext()或 Activity.getApplication()輕松得到Application對象。
5. 避免創(chuàng)建不必要的對象: 就是避免創(chuàng)建短命的臨時對象。減少對象的創(chuàng)建就能減少垃圾收集,進而減少對用戶體驗的影響。
例如:頻繁操作一個字符串時,使用StringBuffer代替String。
對于所有所有基本類型的組合:int數(shù)組比Integer數(shù)組好,這也概括了一個基本事實,兩個平行的int數(shù)組比?(int,int)對象數(shù)組性能要好很多。.避免使用浮點數(shù)
通常的經(jīng)驗是,在Android設(shè)備中,浮點數(shù)會比整型慢兩倍。
7. 使用實體類比接口好
假設(shè)你有一個HashMap對象,你可以將它聲明為HashMap或者Map:
Map map1 = new HashMap();
HashMap map2 = new HashMap();
哪個更好呢?
按照傳統(tǒng)的觀點Map會更好些,因為這樣你可以改變他的具體實現(xiàn)類,只要這個類繼承自Map接口。傳統(tǒng)的觀點對于傳統(tǒng)的程序是正確的,但是它并不適合嵌入式系統(tǒng)。調(diào)用一個接口的引用會比調(diào)用實體類的引用多花費一倍的時間。如果HashMap完全適合你的程序,那么使用Map就沒有什么價值。如果有些地方你不能確定,先避免使用Map,剩下的交給IDE提供的重構(gòu)功能好了。(當(dāng)然公共API是一個例外:一個好的API常常會犧牲一些性能)
8. 訪問成員變量比訪問本地變量慢得多
for循環(huán):不要在for的第二個條件中調(diào)用任何方法
反例:for(int?i?=0;?i?<?this.getCount();?i++)?{}
正例:int?count?=?this.mCount;? int?count?=?this.getCount();
for(int?i?=0;?i?<?count;?i++)??{
}
9. 資源類對象在不使用的時候,應(yīng)該及時關(guān)閉它們,方便它們的緩存數(shù)據(jù)能夠及時回收。
例如:Cursor、File文件等都需要在finally中關(guān)閉資源性對象,避免在異常情況下資源對象未被釋放的隱患
10. 注冊廣播接收器、注冊觀察者等需要在不使用的時候取消注冊。
例如:假設(shè)在Activity中,監(jiān)聽系統(tǒng)的電話服務(wù),可以在Activity中定義一個PhoneStateListener的對象,同時將它注冊到TelephoneManager服務(wù)中。對于Activity對象,理論上要求Activity退出后該Activity的對象就會被釋放掉。但是如果在釋放Activity對象時,忘記取消之前注冊的PhoneStateListener對象,則會導(dǎo)致Activity無法被GC回收。如果不斷的進出這個Activity,則最終會由于大量的Activity對象沒有辦法被回收而引起頻繁的GC情況,甚至導(dǎo)致Out Of Memory。
11. 有效的利用系統(tǒng)自帶的資源,Android系統(tǒng)內(nèi)置了大量的資源,比如字串、顏色定義、常用Icon圖片、動畫樣式、及簡單的布局,沒有特殊要求,資源可以在程序中直接引用。這樣不僅減少內(nèi)存的開銷,還可以減少apk的大小。
12. 視圖復(fù)用,使用ViewHolder實現(xiàn)ConvertView復(fù)用,這基本上是所有容器控件的處理方式,如ListView、GridView等。
13. 使用最優(yōu)的數(shù)據(jù)類型,比較少的對象數(shù)時,ArrayMap替換HashMap的使用,避免使用枚舉,枚舉變量非常方便,但不幸的是它會犧牲執(zhí)行的速度和并大幅增加文件體積。
14. 圖片內(nèi)存優(yōu)化
Android提供的多種位圖格式中,最高的是RGB_8888,也是系統(tǒng)默認(rèn)的位圖格式,其他幾種都減少位圖通道,可以減少內(nèi)存開銷,如一些局部圖片、小屏幕手機或者對圖片質(zhì)量要求不高的場景,均可以使用RGB_565,或者ARGB_4444等圖像格式。
- 圖片縮放:inSampleSize、inScaled、inDensity和inTargetDensity
- 位圖內(nèi)存重用:inBitmap的使用,可以結(jié)合LruCache實現(xiàn)。
- 推薦開源庫:picasso、Glide
15. Android 網(wǎng)絡(luò)通信框架Volley。
16. 對象池、線程池的合理使用。
17. 使用IntentService替代Service。
IntentService優(yōu)勢:新開線程;順序處理Intent;執(zhí)行完自動退出。
18. 盡量不要因一兩個特性而使用大體積類庫。
19. 對象不用時最好顯式置為Null可以減少GC開銷。
20. 多了解并使用類庫。
一些例子
1. 當(dāng)處理字串的時候,盡量使用String.indexOf(),String.lastIndexOf()等特殊實現(xiàn)的方法。這些方法都是使用C/C++實現(xiàn)的,比起Java循環(huán)快10到100倍。
2. System.arraycopy方法在有JIT的Nexus One上,自行編碼的循環(huán)快9倍。
3. android.text.format包下的Formatter類,提供了IP地址轉(zhuǎn)換、文件大小轉(zhuǎn)換等方法;DateFormat類,提供了各種時間轉(zhuǎn)換,都是非常高效的方法。
4. TextUtils類,對于字符串處理Android為我們提供了一個簡單實用的TextUtils類,如果處理比較簡單的內(nèi)容不用去思考正則表達式不妨試試這個在android.text.TextUtils的類
5. 高性能MemoryFile類,對于I/O需要頻繁操作的,主要是和外部存儲相關(guān)的I/O操作,MemoryFile通過將 NAND或SD卡上的文件,分段映射到內(nèi)存中進行修改處理,這樣就用高速的RAM代替了ROM或SD卡,性能自然提高不少,對于Android手機而言同時還減少了電量消耗。該類實現(xiàn)的功能不是很多,直接從Object上繼承,通過JNI的方式直接在C底層執(zhí)行。
內(nèi)存優(yōu)化工具
推薦內(nèi)存分析工具:Memory Monitor? 適用于Android Studio
推薦內(nèi)存泄露分析工作:MAT 適用于eclipse、Android Studio
內(nèi)存泄露監(jiān)控工具:LeakCanary
本文由 @虛偽的溫柔 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來自 unsplash,基于 CC0 協(xié)議
不錯,不過有點過于基礎(chǔ)了。對于性能優(yōu)化這種的,我覺得產(chǎn)品經(jīng)理還是提供一個標(biāo)準(zhǔn)就好,具體細(xì)節(jié)還是開發(fā)定。況且你說的這些基本上是開發(fā)平時要求避免的錯誤,提交代碼的時候都得技術(shù)負(fù)責(zé)人審核才行,你列的這些還是更適合初學(xué)者。