ANDROID 開發規範總結
基本原則
工欲善其事,必先利其器
充分利用好工具,讓電腦代替人腦
最高境界是不寫任何代碼
和產品人員充分討論,仔細評估待實現的功能,明確方案,不做無用功(最好能把需求砍掉J)
爲質量負責
提交代碼前仔細檢查,找同事幫忙review
如果迫不得已,挖坑前做好標記(TODO)
工具和開發環境
開發推薦使用eclipse,或者類eclipse環境
配置好Android Formatter
配置好Save Actions
Formatter配置
Eclipse -> Window -> Preferences
Import 導入相應的formatter.xml文件
Save Actions配置
eclipse -> Window -> Preferences
配置成如上的形式就可以了。
UI編碼規範
不要阻塞UI線程
1、UI線程內不能做耗時操作,如文件讀寫、數據庫操作、邏輯運算等,建議每次調用耗時不超過10ms,如果超過,建議在工作線程內完成。
2、使用trace view查找耗時方法。
3、使用StrictMode監測耗時操作。
優化高頻率運行的代碼
1、不頻繁進行findViewById、getString…等查找資源的操作, 應使用臨時對象緩存。
2、避免頻繁創建對象
–自定義View不能每幀刷新都去創建新的Paint、Rect、Matrix等對象,應使用臨時對象緩存,一次性創建並初始化,每次直接使用。
–當需要重複使用Bitmap時,不要頻繁進行decode,而應將其緩存在cache中。(注:安卓3.0以下可使用軟引用cache,3.0以上使用LRU cache並需自己做好內存控制。 爲了統一和適配,建議使用後者”)。
避免過度刷新
主要是item很多的ListView的過度刷新
1、 不要頻繁調用Adapter的notifyDataSetChanged方法,只更新需要被更新的行。
常見的場景:後臺頻繁更新數據,界面接收到回調後直接notifyDataSetChanged。正確的方法:判斷後臺數據對應的行是否可見,然後刷新該View。
2、listview滑動的過程中少調用notifyDataSetChanged。
3、Adapter需使用複用機制,不能每次getView都去重新inflate, 應儘量利用convertView 和 ViewHolder來實現複用機制。
佈局扁平化
1、 多使用merge、ViewStub標籤。
2、使用RelativeLayout代替多級Linearlayout。
3、使用hierarchy view排查佈局問題。
不使用大尺寸圖片
1、使用BitmapFactory類的decode函數生成bitmap時,調整採樣間隔和縮放尺寸,進行預縮放處理
2、避免使用多套分辨率圖片
爲了保證不同分辨率手機ui效果,可能會在hdpi、xhdpi等目錄下各保持一份圖片,這樣做會增加apk體積,儘量只放一套圖片,然後指定View的高寬,在不同分辨率下定義不同的dimen。
正確使用inflate方法
不正確的使用inflate(Contextcontext, int resource, ViewGroup root)方法導致View Hierarchy多嵌套了一層,會導致View效率低下。
錯誤的作法:
正確的做法:
解決辦法:在inflate第三個參數給定root的時候,應該在xml文件中用merge標籤消除嵌套,並且在代碼中設置相關屬性(xml文件中使用merge標籤,對這一標籤的任何屬性都將失效,包括id,可以看作沒有這一層)。
使用ColorFilter節省圖片資源
一個按鈕擁有多種狀態,爲滿足這些狀態使用了不同的切圖
儘可能的使用ColorFilter,使用ColorFilter可節省50%內存使用
界面元素儘量少且簡單
如果一個Activity展示的元素過多,肯定會影響性能,可以考慮下面的方法:
1、把業務邏輯分拆到不同的界面。
2、使用Fragment展示不同的界面。
3、使用自定義Layout展示不同的界面,不同的情況切換不同的Layout。
UI邏輯和業務邏輯分離
如果activity邏輯很複雜,建議將UI和業務邏輯放到單獨的類實現,用Message傳遞消息,
Adapter數據變化問題
如果在非ui線程修改Adapter內容(增加item),會拋出下面的異常:
java.lang.IllegalStateException: Thecontent of the adapter has changed but ListView did not receive a notification.Make sure the content of your adapter is not modified from a background thread,but only from the UI thread
修改方法是在UI線程中修改,可以通過Handler解決數據傳遞問題。
使用include複用layout
Include可以減少重複資源,佈局文件更清晰。
設置窗口背景爲null
<item name="android:windowBackground">@null</item>
可以省去window背景的繪製,提高界面效率
實踐經驗
修復BUG時,避免簡單粗暴
修復BUG時,要儘量找到問題的根本原因。不要直接加上try/catch完事。
避免Context對象使用強制類型轉換
避免使用Context轉換爲Activity,禁止使用Context轉換爲Application。
持有Context對象
儘量用context.getApplicationContext代替
誰申請誰釋放原則
Receiver的註冊和註銷,包括Android的和LocalBroadcastManager
Service的bind和unbind
一定要保證成對出現,否則導致內存泄漏
Fragment的細節
Fragment的onCreateView/onDestroy/handleMessage,要判斷Activity是否爲空,是否finish
Fragment繼承注意事項
繼承Fragment的子類,其構造函數必須是無參數的,需要的Activity父對象可以通過onAttach(Activity)來傳遞。
public Activity mContext;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mContext = activity;
}
否則會報告如下錯誤:
Caused by:android.support.v4.app.Fragment$InstantiationException: Unable to instantiatefragment alj: make sure class name exists, is public, and has an emptyconstructor that is public
at android.support.v4.app.Fragment.instantiate(Fragment.java:395) com.qihoo360.mobilesafe.ui.fragment.settings.SettingsView -> alj
at android.support.v4.app.FragmentState.instantiate(Fragment.java:96)
atandroid.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1726)
at android.suppo
Dialog的show/dismiss
需要判斷Activity是否finish
AsyncTask的onPost
需要判斷Activity是否finish
Android的Receiver上下文
Android的Receiver上下文是限制上下文,不能用其Context去bindService操作
Handler/Runnable內存泄漏
要小心Handler/Runnable對Activity等的長期持有
AsyncTask內存泄漏
要小心AsyncTask對Activity等的長期持有
Toast使用
Toast最好在UI線程中啓動,否則可能會報錯:
04-17 19:04:29.424: E/CrashHandler(11689):Crash Log BEGIN
04-17 19:04:29.424: E/CrashHandler(11689):java.lang.RuntimeException: Can't create handler inside thread that has notcalled Looper.prepare()
04-17 19:04:29.424: E/CrashHandler(11689):at android.os.Handler.<init>(Handler.java:121)
04-17 19:04:29.424: E/CrashHandler(11689):at android.widget.Toast$TN.<init>(Toast.java:317)
04-17 19:04:29.424: E/CrashHandler(11689):at android.widget.Toast.<init>(Toast.java:91)
明文字符串
儘量不要在傳輸中直接傳輸明文字符串。