天天看點

android 程式設計規範 check list

<b>規範及注意</b>

<b></b>

<b>解釋及說明</b>

打開了資源,要記得關閉資源。要盡量晚地擷取,盡量早地釋放。

 

使用asynctask、線程、intentservice或自定義背景服務來處理髒活

確定你設計的布局簡單、簡練和淺層 

setcontentview()幾乎占用了從oncreate()開始到onresume()結束之間所有時間的99%

減少建立對象的數量。消除不必要的對象,或者推遲建立對象

采用嵌套的線性布局會深化布局層次,進而導緻布局和按鍵處理變慢。

減少布局層次的技巧是用&lt;merge /&gt;标簽來合并布局。 如果你的布局的最上層也是一個framelayout,就可以用&lt;merge /&gt;标簽代替它,減少一層布局

重用布局使用&lt;include /&gt; 标簽

viewstub推遲初始化是個友善的技術,可以推遲執行個體化,提高性能,還可能會節省記憶體

讓你應用程式的資源适合目标裝置 

如果你添加了可利用的龐大圖像資源,需要裝入和調整大小,就無法有效地使用其他的應用程式資源

從外部擷取資料(dex, html, apk)時,一定要校驗資料可靠性,防止資料被第三方而已篡改

manifest中activity節點若非必要,不要添加intent-filter(添加就意味着可以被外部其他應用或程序啟動)

從安全角度不要使用broadcast,廣播的傳播性是不可控的,而且容易被劫持,資訊被截取。(應用内廣播可以參考supportv4包中的localbroadcastmanager。)

敏感資訊輸入使用自定義鍵盤

在代碼中小心使用runtime.exec方法,尤其是運作參數由使用者輸入産生時,一定要驗證參數的合理合法性

内部元件從intent擷取資料時,注意判斷null情況

webview禁止使用savepassword(true)方法

不要自己拼接sql,防止sql注入攻擊

不要使用android預設的aes加密

謹慎使用service,service無job第一時間關閉service,讓service在不必要的情況下運作是記憶體管理上最大的錯誤之一

service啟動之後,系統會一直保持service的運作,service占用的記憶體會一直無法釋放

隻要目前螢幕顯示需要時,才将bitmap放入記憶體,如果原bitmap的分辨率偏高,就把它縮寫

一定要記住增加bitmap的分辨率會導緻記憶體占用呈指數上漲

使用android優化過的集合,比如: sparsearray, sparsebooleanarray,andlongsparsearray 

java中的hashmap在記憶體方面相當低效,每個kv對都需要配置設定一個map.entry來存放,向hashmap中存放一個entry會配置設定一個額外的entry,占用大概32 位元組

避免使用枚舉

enum比常量要多占用2倍的記憶體

謹慎使用抽象類和抽象方法

通常抽象被看做是一種好的程式設計習慣,但是抽象有很大的開銷:需要執行更多的代碼、執行更長時間、占用更多記憶體。

使用nano protobufs序列化資料

pb是google的平台獨立、語言獨立、可擴充的序列化工具;相對于xml更小、更快、更簡單。

避免使用依賴注入架構

依賴注入架構能簡化代碼,為測試、修改配置等提供很友善的環境。但是,但這些架構會有很多掃面注解的初始化,這些工作很耗時并且占用大量記憶體。

謹慎使用第三方類庫

大部分第三方類庫不是針對移動用戶端設計,如果在移動裝置上使用并不高效。至少在使用前,你應該對這些類庫進行優化。

使用proguard清除無用代碼

使用 zipalign對apk進位元組對齊,不然會耗費更多記憶體

多程序需謹慎使用-會增加記憶體占用,大部分app不需要多程序

一個什麼都不運作的空程序大概占用1.4mb記憶體,一個隻運作了一個非常非常簡單的界面的程序會占用4m記憶體

在記憶體緊張時釋放記憶體

當裝置的記憶體變少是,ontrimmemeory(int)方法會被調用

ui渲染程式要快速,避免卡頓産生

android系統每隔16ms發出vsync信号,觸發對ui進行渲染,如果每次渲染都成功,這樣就能夠達到流暢的畫面所需要的60fps,為了能夠實作60fps,這意味着程式的大多數操作都必須在16ms内完成

避免overdraw(過度繪制),避免螢幕上的某個像素在同一幀的時間内被繪制了多次。

會浪費大量的cpu以及gpu資源,可以在開發者選項,打開show gpu overdraw的選項,可以觀察ui上的overdraw情況。 

避免瞬間産生大量的對象

會嚴重占用young generation的記憶體區域,當達到閥值,剩餘空間不夠的時候,也會觸發gc,gc發生的時候,所有的線程都是暫停狀态的

避免在for循環裡面配置設定對象占用記憶體,将trycatch 塊移出循環

避免在ondraw方法裡面執行複雜的操作,避免建立對象

盡量減少喚醒螢幕的次數與持續的時間,合理使用wakelock來處理喚醒的問題

某些非必須馬上執行的操作,例如上傳歌曲,圖檔處理等,可以等到裝置處于充電狀态或者電量充足的時候才進行

平均隻有30%左右的電量是被程式最核心的方法例如繪制圖檔,擺放布局等等所使用掉的,剩下的70%左右的電量是被上報資料,檢查位置資訊,定時檢索背景廣告資訊所使用掉的。

把零散的網絡請求打包進行一次操作,避免過多的無線信号引起的電量消耗

觸發鬧鐘的時間不必過度精确; 盡量使用setinexactrepeating()方法替代setrepeating()方法

使用setinexactrepeating()時,android系統會集中多個應用的重複鬧鐘同步請求,并一起觸發它們。這可以減少系統将裝置喚醒的總次數,以此減少電量消耗

盡量避免讓鬧鐘基于時鐘時間,盡可能使用elapsed_realtime

如果方法不通路對象的字段,可以選擇static而不是virtual

方法是static類型的,這樣方法調用将快15%-20%

進本類型和string類型的常量聲明為static final

類初始化時若引用了靜态final常量不再需要執行clinit()方法,常量已直接使用到dex檔案裡

避免内部的getters/setters

c++或者java和c#中推薦使用方法封裝變量的通路,通過内聯技術可以優化變量的通路速度。但是android中方法調用時比較耗費資源的,是以對外部類可以通過方法調用範文屬性,但是類的内部可以直接使用屬性。

沒有jit(just in time及時編譯)時,直接通路比getter快3x倍,有jit時快7x倍

使用增強的for循環for-each,盡量避免使用iterator來執行周遊操作

for(object a : arrays)方式3x倍快于iterable和arrays.get(index)方式周遊

使用包級通路而不是内部類的私有通路,但在公開的api中你不能這樣做

避免使用float類型

float類型的資料存取速度是int類型的一半,盡量優先采用int類型

使用庫函數

系統函數有時可以替代第三方庫,并且還有彙編級别的優化,他們通常比帶有jit的java編譯出來的代碼更高效

謹慎使用native函數

jit不能在這種情況下做優化,收集資源困難,不同平台不同代碼

合理的利用充電、電量不足、聯網等事件停止或執行響應的耗性能操作

android5.0提供了jobscheduler實作此能力

降低網絡操作

網絡操作相對來說是比較耗電的行為,激活瞬間,發送資料的瞬間,接收資料的瞬間都有很大的電量消耗

盡量使用android平台提供的既有運動資料,而不是自己去實作監聽采集資料

在activity不需要監聽某些sensor資料的時候需要盡快釋放監聽注冊

可以針對sensor的資料做批量處理,待資料累積一定次數或者某個程度的時候才更新到ui上

為了確定所有的對象能夠正确被釋放,我們需要保證加入對象池的對象和其他外部對象沒有互相引用的關系

要注意lru cache中被淘汰對象的回收,否者會引起嚴重的記憶體洩露

使用lint掃描代碼

開啟strickmode檢測性能

盡量減少png圖檔的大小是android裡面很重要的一條規範

png能夠提供更加清晰無損的圖檔,jpeg就可以達到視覺效果的,可以考慮采用jpeg即可,webp,它是由google推出的一種既保留png格式的優點,又能夠減少圖檔大小的一種新型圖檔格式

對bitmap做縮放的意義很明顯,提示顯示性能,避免配置設定不必要的記憶體

android提供了現成的bitmap縮放的api,叫做createscaledbitmap(),使用這個方法可以擷取到一張經過縮放的圖檔

使用inbitmap屬性可以告知bitmap解碼器去嘗試使用已經存在的記憶體區域

新解碼的bitmap會嘗試去使用之前那張bitmap在heap中所占據的pixel data記憶體區域,而不是去問記憶體重新申請一塊區域來存放bitmap

android4.4前的系統使用webview會出現ashmem的記憶體洩露,另起一個新的程序來啟動webview的activity,activity銷毀的時候,調用system.exit(0),退出程序,徹底釋放記憶體

減少使用反射機制,如果一定要使用,看是否可能增加一層緩存

對傳輸資料根據業務情況壓縮

千萬不要用class.getresrouceasstream(),正确使用context.getresource()

本身android在啟動過程當中就會解析assert檔案放到相應的map裡,采用這種方式則會導緻對所有class進行搜尋并找到相應的類,加上android所有代碼是打在一個apk裡,則搜尋的速度則相當慢

避免不需要的instanceof操作

當複制數組時使用system.arraycop方法

在進行資料庫連接配接和網絡連接配接時使用連接配接池

盡量使用基本資料類型代替對象

可以重寫activity的onnewintent()來處理activity建立後得到新的intent場景

可以通過package manager的setcomponentenablesetting啟動停止manifest裡的receiver/activity/service,已減少不必要的開銷

handler類的定義應該是static的,否則容易産生記憶體洩露

如果handler是個内部類,那 麼它也會保持它所在的外部類的引用。為了避免洩露這個外部類,應該将handler聲明為static嵌套類,并且使用對外部類的弱應用。

private static class myhandler extends handler {

        private weakreference&lt;settingactivity&gt; mactivity;

        public myhandler(settingactivity activity){

            mactivity = new weakreference&lt;settingactivity&gt;(activity);

        }

        public void handlemessage(android.os.message msg) {......}

快速異步儲存場景使用shared preference.editor.apply(),commit是同步儲存

考慮效率是以,android的系統設計使得在任何時候都沒有必要手動關閉資料庫。

如果系統需要額外的資源,應用程式将會關閉,與其關聯的資料庫也會關閉

資料庫查詢使用cursor注意要異步查詢,并在使用後關閉,防止記憶體洩露

在activity和fragement裡加載耗時資料使用loadermanager異步加載

start方式啟動service導緻服務一直存在比較耗費資源,bind方式可以使service随activity啟動和終止,并提供友善的互動接口

盡量為每一個view設定contentdescription屬性

語音工具可直接朗讀

使用passive location provider可降低定位能耗,适合背景讀取位置資訊

當且僅當其他應用請求位置更新時此provider才會收到位置更新

使用intent.resolveactivity(getpackagemanager()) != null判斷是否有應用處理intent

避免沒有處理的應用時crash

避免直接加載超清圖檔到記憶體,通過縮放decoderesource技術加載使用平台顯示分辨率即可

每個應用一般最大占用16m記憶體,超過會造成crash

onpause()、 onstop()、ondestroy()方法中需要适當的釋放資源

使用網絡前最好檢測可用性和網絡類型,大資料最好在vifi下上傳下載下傳

盡量避免polling方式輪訓,可以使用長連結推送架構替代,即使必須使用考慮用最低的頻率

不要在ondraw()方法裡建立對象

可能會導緻記憶體垃圾回收而造成卡頓

如果你的方法是傳回string并且傳回值會被append到一個stringbuffer上,請調整設計,避免建立臨時存在在對象

避免建立不必要的短時間存在的對象,減少記憶體使用

int數組比integer數組要節省資源,兩個一維的資料比一個二維數組要節省資源

通過一個對象同時存儲對象a和b不如分别通過兩個數組存儲a和b性能好,當然如果封裝a和b是為了其他地方更好的引用那麼可以忽略這部分影響

内部類通路外部類屬性時,内部類盡量是包通路權限而不是private。

private的内部類通路外部類的private屬性時,通常認為不合法,但vm會自動添加靜态方法實作能夠通路

沒有jit時通路接口的方法比直接通路精确類型的方法性能好,有jit時基本沒差别

traceview分析時會禁止jit,容易導緻執行時間分析的不準确,多耗費的時間可能因為jit編譯而優化掉

性能優化前請確定你遇到了性能問題,并且你可以測量性能優化的效果

layout嵌套場景使用layout_weight屬性會很耗費性能,在使用listview和gridview時更要注意

每一個子節點都要計算兩次來計算布局空間