(同事分享) android高性能編程中需要注意的問(wèn)題

1.盡量少的聲明全局變量


2.聲明全局靜態(tài)變量,一定要加final聲明


3.聲明非靜態(tài)的全局變量,最好不要初始化任何值,在使用到的地方,在進(jìn)行初始化


4.函數(shù)中若干次使用全局變量,應(yīng)該將全局變量賦值給本地變量,然后直接使用本地變量


**5.能用Int,不要使用浮點(diǎn)數(shù) **


6.能用乘法不用除法


7.盡量避免使用geter和setter方法


8.在Activity的onCreate函數(shù)中,盡量做少的事。


9.在Activity中聲明的靜態(tài)數(shù)組或者靜態(tài)代碼塊,重構(gòu)到單獨(dú)的一個(gè)類里。


10.布局文件要盡可能的優(yōu)化,減少布局的解析時(shí)間 。 盡量減少布局的嵌套層次


11.Activity啟動(dòng)后開始進(jìn)行異步線程的加載,最好delay一下。再開啟線程


12.對(duì)于存在于集合中的Bean對(duì)象,盡可能少的聲明變量。能用int 就不要用long.聲明的string等復(fù)雜變量,最好不要進(jìn)行初始化。


13.使用線程,一定要給它傳一個(gè)名字,然后需要定義線程的優(yōu)先級(jí)


14.在使用集合的時(shí)候,優(yōu)先選擇SparseArray。
Java 中每個(gè)類(包括匿名內(nèi)部類)都占用至少 500字節(jié)左右的代碼;
每個(gè)類的實(shí)例會(huì)在 RAM 中占用大約 12 ~ 16 字節(jié)的內(nèi)存;
每向 HashMap 中添加一個(gè) Entry 時(shí),新生成的 Entry 占用大約 32 個(gè)字節(jié)。


15.盡量避免使用枚舉
枚舉類型 Enum 會(huì)比靜態(tài)常量占用更多的內(nèi)存;


16.工具方法盡量寫成是靜態(tài)方法


17.線程間同步盡量使用開銷小的同步鎖


18.在使用集合類的時(shí)候,如果已知數(shù)據(jù)的規(guī)模,在初始化的時(shí)候,就設(shè)定好默認(rèn)大小。


19.私有內(nèi)部類訪問(wèn)外部類的私有變量,要將變量修改為包繼承權(quán)限


20.對(duì)于開銷大的算法,且不止是執(zhí)行一次的,要使用緩存策略


21.避免在繪制或者解析布局的時(shí)候,分配對(duì)象。例如onDraw方法


22.不要給布局寫無(wú)用的參數(shù),例如RelativeLayout,寫layout_weight屬性


23.盡量減少布局的嵌套層數(shù)。例如包含一個(gè)ImageView和TextView的線性布局,可以用CompoundDrawable的TextView來(lái)代替


24.盡量用Android提供的SparseArray來(lái)代替HashMap


25.如果LinearLayout用于嵌套的layout空間計(jì)算,它的android:baselineAligned設(shè)置為false,可以加速layout計(jì)算


26.用FloatMath代替Math


27.盡量避免嵌套的使用layout_weight,那樣會(huì)影響執(zhí)行效率


28.如果為rootView設(shè)置了背景,那么會(huì)先用Theme指定的背景繪制一遍,然后才用指定的背景繪制,這叫做"overdraw",可以通過(guò)theme的background為null來(lái)避免


29.不要有無(wú)用的任何資源或者文件


官網(wǎng)文章
如何控制應(yīng)用程序使用的內(nèi)存?
1. 記得關(guān)閉啟動(dòng)的服務(wù)
當(dāng)服務(wù)中的任務(wù)完成后,要記得停止該服務(wù)。可以考慮使用 IntentService,因?yàn)镮ntentService 在完成任務(wù)后會(huì)自動(dòng)停止。


2. UI 不可見時(shí)釋放資源
在 onStop 中關(guān)閉網(wǎng)絡(luò)連接、注銷廣播接收器、釋放傳感器等資源;
在 onTrimMemory() 回調(diào)方法中監(jiān)聽TRIM_MEMORY_UI_HIDDEN 級(jí)別的信號(hào),此時(shí)可在 Activity 中釋放 UI 使用的資源,大符減少應(yīng)用占用的內(nèi)存,從而避免被系統(tǒng)清除出內(nèi)存。


3. 內(nèi)存緊張時(shí)釋放資源
運(yùn)行中的程序,如果內(nèi)存緊張,會(huì)在 onTrimMemory(int level) 回調(diào)方法中接收到以下級(jí)別的信號(hào):
TRIM_MEMORY_RUNNING_MODERATE:系統(tǒng)可用內(nèi)存較低,正在殺掉 LRU緩存中的進(jìn)程。你的進(jìn)程正在運(yùn)行,沒有被殺掉的危險(xiǎn)。
TRIM_MEMORY_RUNNING_LOW:系統(tǒng)可用內(nèi)存更加緊張,程序雖然暫沒有被殺死的危險(xiǎn),但是應(yīng)該盡量釋放一些資源,以提升系統(tǒng)的性能(這也會(huì)直接影響你程序的性能)。
TRIM_MEMORY_RUNNING_CRITICAL:系統(tǒng)內(nèi)存極度緊張,而LRU緩存中的大部分進(jìn)程已被殺死,如果仍然無(wú)法獲得足夠的資源的話,接下來(lái)會(huì)清理掉 LRU 中的所有進(jìn)程,并且開始?xì)⑺酪恍┫到y(tǒng)通常會(huì)保留的進(jìn)程,比如后臺(tái)運(yùn)行的服務(wù)等。
當(dāng)程序未在運(yùn)行,保留在 LRU 緩存中時(shí), onTrimMemory(int level) 中會(huì)返回以下級(jí)別的信號(hào):
TRIM_MEMORY_BACKGROUND:系統(tǒng)可用內(nèi)存低,而你的程序處在 LRU的頂端,因此暫時(shí)不會(huì)被殺死,但是此時(shí)應(yīng)釋放一些程序再次打開時(shí)比較容易恢復(fù)的 UI 資源。
TRIM_MEMORY_MODERATE:系統(tǒng)可用內(nèi)存低,程序處于 LRU的中部位置,如果內(nèi)存狀態(tài)得不到緩解,程序會(huì)有被殺死的可能。
TRIM_MEMORY_COMPLETE:系統(tǒng)可用內(nèi)存低,你的程序處于 LRU尾部,如果系統(tǒng)仍然無(wú)法回收足夠的內(nèi)存資源,你的程序?qū)⑹紫缺粴⑺馈4藭r(shí)應(yīng)釋放無(wú)助于恢復(fù)程序狀態(tài)的所有資源。
注:該 API 在版本 14 中加入。舊版本的onLowMemory() 方法,大致相當(dāng)于 onTrimMemory(int level) 中接收到 TRIM_MEMORY_COMPLETE 級(jí)別的信號(hào)。
另:盡管系統(tǒng)主要按照 LRU 中順序來(lái)殺進(jìn)程,不過(guò)系統(tǒng)也會(huì)考慮程序占用的內(nèi)存多少,那些占用內(nèi)存高的進(jìn)程有更高的可能性會(huì)被首先殺死。


4. 確定你的程序應(yīng)該占用多少內(nèi)存
可以通過(guò) getMemoryClass()來(lái)獲取你的程序被分配的可用內(nèi)存,以 M 為單位。
你可以通過(guò)在 <application> 標(biāo)簽下將 largeHeap 屬性設(shè)為 true 來(lái)要求更多的內(nèi)存,這時(shí)通過(guò) getLargeMemoryClass() 方法來(lái)獲取可用內(nèi)存。
大部分應(yīng)用程序不需要使用此功能,因此使用該標(biāo)簽前,確認(rèn)你的程序是否真的需要更多內(nèi)存。使用更多內(nèi)存會(huì)對(duì)整個(gè)系統(tǒng)的性能產(chǎn)生影響,而且當(dāng)程序進(jìn)入 LRU時(shí)會(huì)更容易首先被系統(tǒng)清理掉。


5. 正確使用 Bipmap,避免浪費(fèi)內(nèi)存
如果你的 ImageViwe 的尺寸只有 100 * 100,那么沒有必要將一張 2560 * 1600 的圖片整個(gè)加載入內(nèi)存。


6. 使用 Android提供的優(yōu)化過(guò)的數(shù)據(jù)結(jié)構(gòu)
如 SparseArray, SparseBooleanArray, LongSparseArray 等,相比 Java 提供的 HashMap,這些結(jié)構(gòu)更節(jié)省內(nèi)存。


7. 始終對(duì)內(nèi)存使用情況保持關(guān)注
枚舉類型 Enum 會(huì)比靜態(tài)常量占用更多的內(nèi)存;
Java 中每個(gè)類(包括匿名內(nèi)部類)都占用至少 500字節(jié)左右的代碼;
每個(gè)類的實(shí)例會(huì)在 RAM 中占用大約 12 ~ 16 字節(jié)的內(nèi)存;
每向 HashMap 中添加一個(gè) Entry 時(shí),新生成的 Entry 占用大約 32 個(gè)字節(jié)。


8. 謹(jǐn)慎使用第三方類庫(kù)
這些外部類庫(kù)可能原先并非針對(duì)移動(dòng)平臺(tái),因此未進(jìn)行過(guò)優(yōu)化,在使用前應(yīng)注意。另外盡量不要因?yàn)橐粌蓚€(gè)特性而使用一個(gè)體積很大的類庫(kù)。


9. 使用 ProGuard
使用 ProGuard 移除無(wú)用的代碼并重命名一些類、字段、方法等,使你的代碼更緊湊,節(jié)省內(nèi)存空間。


10. 使用 zipalign
zipaligned 對(duì)最終打包的 apk進(jìn)行字節(jié)對(duì)齊。
注:Google Play 不接受未對(duì)齊過(guò)的 apk。


11. 分析內(nèi)存使用情況
如果已經(jīng)獲得一個(gè)相對(duì)穩(wěn)定的版本,應(yīng)對(duì)程序整個(gè)生命周期的內(nèi)存使用狀況進(jìn)行分析。


12. 使用多個(gè)進(jìn)程
如果程序需要執(zhí)行大量的后臺(tái)工作,可考慮將程序分為兩個(gè)進(jìn)程,一個(gè)進(jìn)程負(fù)責(zé) UI,另一個(gè)進(jìn)程負(fù)責(zé)后臺(tái)任務(wù)。比如音樂(lè)播放器。

代碼示例:

<serviceandroid:name=".PlaybackService"android:process=":background"/>
** android:process屬性的值以“:”開頭,名稱可任意選取。**
在決定是否使用多進(jìn)程前,應(yīng)注意,一個(gè)不執(zhí)行任何任務(wù)的空進(jìn)程至少也要占用 1.4 MB內(nèi)存。
另外要注意進(jìn)程的相互依賴性,比如如果將 ContentProvider 放在 UI 進(jìn)程中,而后臺(tái)任務(wù)進(jìn)程也需要調(diào)用 ContentProvider,就會(huì)導(dǎo)致 UI 進(jìn)程一直保留在 RAM 中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容