編輯:關於Android編程
強制:編程時必須遵守的規定,含有強制字樣或字體用加粗式樣標注。
推薦:編程時推薦遵守的規定,字體用普通式樣標注。
避免超過 2000 行的源文件。
每個 Java 源文件都包含一個單一的公共類或接口。若私有類和接口與一個公共類相關聯,可以將它們和公共類放入同一個源文件。公共類必須是這個文件中的第一個類或接口。
Java 源文件還遵循以下規則:
所有的源文件都應該在開頭有一個的注釋,其中列出版本信息、日期和版權聲明。
/* * Copyright (c) 2014 SIMCOM, Inc. * All Rights Reserved. * SIMCOM Proprietary and Confidential. */
在多數 Java 源文件中,第一個非注釋行是包語句,在它之後可以跟引入語句。
package com.android.sim; import java.io.IOException;
在導入包時當完全限制代碼所使用的類的名字,盡量少用通配符的方式,但導入一些通用包,或用到一個包下大部分類時,則可是使用通配符方式。同一包中的類在導入時應聲明在一起,無效的未使用到的引用要即時刪除。
下表(強制)描述了類和接口聲明的各個部分以及它們出現的先後次序。
4 個空格作為縮進排版的一個單位,不使用制表符 tab。
8 個空格作為換行後的縮進,包括函數調用和賦值。
Instrument i = someLongexpression_r(that, NotFit, on, one, line); // 推薦 Instrument i = someLongexpression_r(that, NotFit, on, one, line); // 避免
盡量避免一行的長度超過 100 個字符。
例外:如果注釋行包含了超過 100 個字符的命令示例或者 url 文字,為了便於剪切和復制,其長度可以超過 100 個字符。
例外:import 行可以超過限制,因為很少有人會去閱讀它。這也簡化了編程工具的寫入操作。
大括號不單獨占用一行,應緊接著上一行書寫。
class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } } }
我們需要用大括號來包裹條件語句塊。不過也有例外,如果整個條件語句塊(條件和語句本身)都能容納在一行內,也可以(但不是必須)把它們放入同一行中。也就是說,這是合法的:
if (condition) { body(); } // 推薦 if (condition) body(); // 避免 if (condition) body(); // 錯誤
當一個表達式無法容納在一行內時,可以依據如下一般規則斷開:
/** * 一句話方法描述 * 方法詳細描述 * @param 參數名 參數描述 * @param 參數名2 參數描述 * @return 返回值類型說明 * @throws Exception 異常說明 * @see 類/方法/成員 */
成員變量和常量需要使用javadoc形式的注釋,以說明當前變量或常量的含義。
/** * 成員變量描述 */ private String test; /** 成員變量描述 */ private int hello;
推薦一行一個聲明,因為這樣以利於寫注釋。
int level; // indentation level int size; // size of table
注意:上面的例子中,在類型和標識符之間放了一個空格,另一種被允許的替代方式是使用制表符。
int level; // indentation level int size; // size of table char username; // username
盡量在聲明局部變量的同時初始化。唯一不這麼做的理由是變量的初始值依賴於某些先前發生的計算。
只在代碼塊的開始處聲明變量(一個塊是指任何被包含在大括號“{“和”}“中間的代碼)。不要在首次用到該變量時才聲明之。這會把注意力不集中的程序員搞糊塗,同時會妨礙代碼在該作用域內的可移植性。
void myMethod() { int int1 = 0; // beginning of method block if (condition) { int int2 = 0; // beginning of “if” block ... } }
避免聲明的局部變量覆蓋上一級聲明的變量。例如,不要在內部代碼塊中聲明相同的變量名:
int count; ... myMethod() { if (condition) { int count = 0; // 避免 ... } ... }
當編寫類和接口是,應該(強制)遵守以下格式規則:
class Sample extends Object { int ivar1; int ivar2; Sample(int i, int j) { ivar1 = i; ivar2 = j; } int emptyMethod() {} ... }
每行之多包含一條語句,例如:
argv++; // 推薦 argc--; // 推薦 argv++; argc--; // 避免
復合語句是包含在大括號中的語句序列,形如”{ 語句 }“。例如下面各段。
一個帶返回值的return語句不使用小括號”()“,除非它們以某種方式使返回值更為顯見。例如:
return; return myDisk.size(); // 避免 return (size ? size : defaultSize); // 避免
if-else語句應該具有如下格式:
if (condition) { statements; } if (condition) { statements; } else { statements; } if (condition) { statements; } else if (condition) { statements; } else{ statements; }
注意:if語句總是用”{“和”}“括起來,避免使用如下容易引起錯誤的格式:
if (condition) // 避免 statement;
一個for語句應該具有如下格式:
for (initialization; condition; update) { statements; }
當在for語句的初始化或更新子句中使用逗號時,避免因使用三個以上變量,而導致復雜度提高。若需要,可以在for循環之前(為初始化子句)或for循環末尾(為更新子句)使用單獨的語句。
一個while語句應該具有如下格式:
while (condition) { statements; }
do { statements; } while (condition);
一個switch語句應該具有如下格式:
switch (condition) { case ABC: statements; /* falls through */ case DEF: statements; break; case XYZ: statements; break; default: statements; break; }
每當一個case順著往下執行時(因為沒有break語句),通常應在break語句的位置添加注釋。上面的示例代碼中就包含注釋/* falls through */。
一個try-catch語句應該具有如下格式:
try { statements; } catch (ExceptionClass e) { statements; } try { statements; } catch (ExceptionClass e) { statements; } finally { statements; }
空行將邏輯相關的代碼段分隔開,以提高可讀性。下列情況應該總是使用空行:
下列情況應該使用空格:
while (true) { ... }
a += c + d; a = (a + b) / (c * d); while (d++ = s++) { n++; }
for (expr1; expr2; expr3)
myMethod((byte) aNum, (Object) x); myMethod((int) (cp + 5), ((int) (i + 3)) + 1);
命名規范使程序更易讀,從而更易於理解。它們也可以提供一些有關標識符功能的信息,以助於理解代碼。
包名由全部小寫字母組成,包名的前綴以com開頭,包名後續部分的格式為:
[域名反轉].[項目名].[模塊名].[子模塊名]…
例如:com.android.sim.message.sms
類名是個一名詞,采用大小寫混合的方式,每個單詞的首字母大寫。盡量使你的類名簡潔而富於描述。使用完整單詞,或約定成俗並且使用廣泛的縮寫詞,如url,html,接口和類名規則一至但要使用I前綴。
繼承自系統組件類的命名,後綴必須明確表示出系統組件的類別,Activity類後綴使用Activity,Service類後綴使用Service,BroadcaseReceiver類後綴使用Receiver,ContentProvider使用Provider。
方法名是一個動詞或者動名詞結構,采用大小寫混合的方式,第一個單詞的首字母小寫,其後單詞的首字母大寫,即駝峰命名規則。
以它做什麼來命名,而不是以它怎樣做命名。如doUpdate(),isNumber()。
第一個單詞的首字母小寫,其後單詞的首字母大寫。變量名不應以下劃線或美元符號開頭,盡管這在語法上是允許的。變量名的選用應該易於記憶,即,能夠指出其用途。盡量避免單個字符的變量名,除非是一次性的臨時變量。臨時變量通常被取名為 i,j,k,m 和 n,它們一般用於整型;c,d,e,它們一般用於字符型。
其中系統控件中在後綴中體現控件類型,如下所示:
非 public 的、非 static 的字段名稱以 m 開頭。
static 字段名稱以 s 開頭。
其它字段以小寫字母開頭。
public class MyClass { public int publicField; private static MyClass sSingleton; int mPackagePrivate; private int mPrivate; protected int mProtected; }
類常量的聲明,應該全部大寫,單詞間用下劃線隔開。
static final int MIN_WIDTH = 4; static final int MAX_WIDTH = 999; static final int GET_THE_CPU = 1;
自定義異常的命名必須以Exception為結尾,已明確標示為一個異常。
異常實例一般使用e、ex等,在多個異常時使用該異常名或簡寫加E,Ex等組成,如:SQLEx,ActionEx。
命名必須以全部單詞小寫,單詞間以下劃線分割,並且盡可能的使用名詞或名詞組,即使用 模塊名_功能名稱 來命名。
addressbook_list.xml // 推薦 list_addressbook.xml // 避免
layout中所使用的id命名必須以全部單詞小寫,單詞間以下劃線分割,並且盡可能的使用名詞或名詞組,並且要求能夠通過id直接理解當前組件要實現的功能。
EditText名 @+id/book_name_edit // 推薦 EditText名 @+id/textbookname // 避免
采用大小寫混合模式,第一個單詞首字母小寫,其余單詞首字母大寫最後一個單詞為該View 類型的縮寫,格式如下:
邏輯名+View 類型縮寫(View 縮寫參照 8.4 組件名稱縮寫表)。
Button homeBtn
命名必須以全部單詞小寫,單詞間以下劃線分割,並且盡可能的使用名詞或名詞組,格式如下:
main_menu_about main_title common_exit common_app_name
layout中使用的所有資源(如drawable,style等)命名必須以全部單詞小寫,單詞間以下劃線分割,並且盡可能的使用名詞或名詞組,即使用模塊名_用途來命名。如果為公共資源,如分割線等,則直接用用途來命名。如:menu_icon_navigate.png
在使用單位時,如果沒有特殊情況,一律使用 sp 作為文字大小的單位,將 dip 作為其他元素的單位。因為這兩個單位是與設備分辨率無關的,能夠解決在不同分辨率的設備上顯示效果不同的問題。另外,在編碼中定義控件的 margin 或 padding 屬性時,SDK 裡面並沒有提供 dip 單位的 api 設置接口,而是提供了默認的 px 設置。
Button btn = new Button(context); LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT); lp.setMargins(0, 0, 0, 0); btn.setTextSize(12); btn.setPadding(0, 0, 0, 0);
這個時候,一般在設置 margin 和 padding 時,應該對要設置的 dip 值轉換為 px 單位,而字體的大小設置中,系統默認給出了 sp 的單位,所以可以不用進行轉換。轉換的方法參考下面的代碼:
/** * 把dip單位轉成px單位 * @param context context對象 * @param dip dip數值 * @return dip對應的px值 */ public static int formatDipToPx(Context context, int dip) { DisplayMetrics dm = new DisplayMetrics(); ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(dm); int dip = (int) Math.ceil(dip * dm.density); return dip; }
避免用一個對象訪問一個類的靜態變量和方法。應該用類名替代。
classMethod(); // 推薦 AClass.classMethod(); // 推薦 anObject.classMethod(); // 避免
位於 for 循環中作為計數器值的數字常量,除了-1,0 和 1 之外,不應被直接寫入代碼。
避免在一個語句中給多個變量賦相同的值,它很難讀懂。
如果類只是用來作為信息傳遞的中間變量,則應該聲明為信令類,即所有的全局變量都是 final 類型,在初始化時賦值。
private final String name; public Foo(String str) { name = str; } public Foo(String str ) { this.str = str; // 避免在構造函數中出現this引用 }
有時,完全忽略異常是非常誘人的。
void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { } // 錯誤 }
絕對不要這麼做。也許你會認為:你的代碼永遠不會碰到這種出錯的情況,或者處理異常並不重要,可類似上述忽略異常的代碼將會在代碼中埋下一顆地雷,說不定哪天它就會炸到某個人了。你必須在代碼中以某種規矩來處理所有的異常。根據情況的不同,處理的方式也會不一樣。可接受的替代方案包括(按照推薦順序):向方法的調用者拋出異常。
void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value); }
根據抽象級別拋出新的異常。
void setServerPort(String value) throws ConfigurationException { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new ConfigurationException("Port " + value + " is not valid."); } }
默默地處理錯誤並在 catch {} 語句塊中替換為合適的值。
/** 設置端口。假如值不是數字則用80代替 */ void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { serverPort = 80; // 服務默認端口 } }
捕獲異常並拋出一個新的 RuntimeException。這種做法比較危險:只有確信發生該錯誤時最合適的做法就是崩潰,才會這麼做。
/** 設置端口,假如值不是數字則程序終止。 */ void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new RuntimeException("port " + value " is invalid, ", e); } }
請記住,最初的異常是傳遞給構造方法的 RuntimeException。如果代碼必須在 Java 1.3 版本下編譯,需要忽略該異常。最後一招:如果確信忽略異常比較合適,那就忽略吧,但必須把理想的原因注釋出來。
/** 假如值不是數字則使用原來的端口號。 */ void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { // 方法記錄:無視無效的用戶輸入。 // 服務端口不會被改變。 } }
有時在捕獲 Exception 時偷懶也是很吸引人的,類似如下的處理方式:
try { someComplicatedIOFunction(); // 可能拋出IOException someComplicatedParsingFunction(); // 可能拋出ParsingException someComplicatedSecurityFunction(); // 可能拋出SecurityException // 其他可以拋出Exception的代碼 } catch (Exception e) { // 一次性捕獲所有exceptions handleError(); // 只有一個通用的處理方法! }
不要這麼做。絕大部分情況下,捕獲頂級的 Exception 或 Throwable 都是不合適的,Throwable 更不合適,因為它還包含了 Error 異常。這種捕獲非常危險。這意味著本來不必考慮的 Exception(包括類似 ClassCastException 的 RuntimeException)被卷入到應用程序級的錯誤處理中來。這會讓代碼運行的錯誤變得模糊不清。這意味著,假如別人在你調用的代碼中加入了新的異常,編譯器將無法幫助你識別出各種不同的錯誤類型。絕大部分情況下,無論如何你都不應該用同一種方式來處理各種不同類型的異常。
本規則也有極少數例外情況:期望捕獲所有類型錯誤的特定的測試代碼和頂層代碼(為了阻止這些錯誤在用戶界面上顯示出來,或者保持批量工作的運行)。這種情況下可以捕獲頂級的 Exception(或 Throwable)並進行相應的錯誤處理。在開始之前,你應該非常仔細地考慮一下,並在注釋中解釋清楚為什麼這麼做是安全的。
比捕獲頂級 Exception 更好的方案:
請記住:異常是你的朋友!當編譯器指出你沒有捕獲某個異常時,請不要皺眉頭。而應該微笑:編譯器幫助你找到了代碼中的運行時(runtime)問題。
Finalizer 提供了一個機會,可以讓對象被垃圾回收器回收時執行一些代碼。
優點:便於執行清理工作,特別是針對外部資源。
缺點:調用 finalizer 的時機並不確定,甚至根本就不會調用。
結論:我們不要使用 finalizers。大多數情況下,可以用優秀的異常處理代碼來執行那些要放入 finalizer 的工作。如果確實是需要使用 finalizer,那就定義一個 close() 方法(或類似的方法),並且在文檔中准確地記錄下需要調用該方法的時機。相關例程可以參見InputStream。這種情況下還是適合使用 finalizer 的,但不需要在 finalizer 中輸出日志信息,因為日志不能因為這個而被撐爆。
當需要使用 foo 包中的 Bar 類時,存在兩種可能的 import 方式:
1. import foo.*;
優點:可能會減少 import 語句。
2. import foo.Bar;
優點:實際用到的類一清二楚。代碼的可讀性更好,便於維護。
結論: 用後一種寫法來 import 所有的 Android 代碼。不過導入 java 標准庫 (java.util.*、java.io.*等) 和單元測試代碼 (junit.framework.*) 時可以例外。
import 語句的次序應該如下:
1. Android imports
2. 第三方庫(com、junit、net、org)
3. java 和 javax
為了精確匹配 IDE 的配置,import 順序應該是:
1. 在每組內部按字母排序,大寫字母排在小寫字母的前面。
2. 每個大組之間應該空一行(android、com、junit、net、org、java、javax)。
3. 原先次序是不作為規范性要求的。這意味著要麼允許 IDE 改變順序,要麼使用 IDE的開發者不得不禁用 import 自動管理功能並且人工維護 import。這看起來比較糟糕。每當說起 java 規范,推薦的規范到處都是。符合我們要求的差不多就是“選擇一個次序並堅持下去。”於是,我們就選擇一個規范,更新規范手冊,並讓 IDE去遵守它。我們期望:不必耗費更多的精力,用 IDE 編碼的用戶就按照這種規則去 import 所有的 package。
基於以下原因,選定了本項規則:
靜態 import 的使用和位置已經成為略帶爭議的話題。有些人願意讓靜態 import 和其它 import 混在一起,另一些人則期望讓它們位於其它 import 之上或者之下。另外,我們還未提到讓所有 IDE 都遵守同一個次序的方法。
因為大多數人都認為這部分內容並不要緊,只要遵守你的決定並堅持下去即可。
局部變量的作用范圍應該是限制為最小的(Effective Java 第 29 條)。使用局部變量,可以增加代碼的可讀性和可維護性,並且降低發生錯誤的可能性。每個變量都應該在最小范圍的代碼塊中進行聲明,該代碼塊的大小只要能夠包含所有對該變量的使用即可。
應該在第一次用到局部變量的地方對其進行聲明。幾乎所有局部變量聲明都應該進行初始化。如果還缺少足夠的信息來正確地初始化變量,那就應該推遲聲明,直至可以初始化為止。
本規則存在一個例外,就是涉及 try-catch 語句的情況。如果變量是用方法的返回值來初始化的,而該方法可能會拋出一個 checked 異常,那麼必須在 try 塊中進行變量聲明。如果需在 try 塊之外使用該變量,那它就必須在 try 塊之前就進行聲明了,這時它是不可能進行正確的初始化的。
// 實例化類cl,表示有序集合 Set s = null; try { s = (Set) cl.newInstance(); } catch(IllegalAccessException e) { throw new IllegalArgumentException(cl + " not accessible"); } catch(InstantiationException e) { throw new IllegalArgumentException(cl + " not instantiable"); } // 集合練習 s.addAll(Arrays.asList(args));
但即便是這種情況也是可以避免的,把try-catch 塊封裝在一個方法內即可。
Set createSet(Class cl) { // 實例化類cl,表示有序集合 try { return (Set) cl.newInstance(); } catch(IllegalAccessException e) { throw new IllegalArgumentException(cl + " not accessible"); } catch(InstantiationException e) { throw new IllegalArgumentException(cl + " not instantiable"); } } ... // 集合練習 Set s = createSet(cl); s.addAll(Arrays.asList(args));
除非理由十分充分,否則循環變量都應該在for語句內進行聲明。
for (int i = 0; i n; i++) { doSomething(i); } for (Iterator i = c.iterator(); i.hasNext(); ) { doSomethingElse(i.next()); }
Annotation 應該位於 Java 語言元素的其它修飾符之前。 簡單的 marker annotation(@Override 等)可以和語言元素放在同一行。 如果存在多個 annotation,或者annotation 是參數化的,則應按字母順序各占一行來列出。
對於 Java 內建的三種 annotation,Android 標准的實現如下:
當需要使用@SuppressWarnings annotation時,必須在前面加上TODO注釋行,用於解釋“不可能消除”警告的條件。通常是標明某個令人討厭的類用到了某個拙劣的接口。
// TODO: 第三方類 com.third.useful.Utility.rotate() 必須采用泛型 @SuppressWarnings("generic-cast") Listblix = Utility.rotate(blax);
如果需要使用@SuppressWarnings annotation,應該重新組織一下代碼,把需要應用 annotation 的語言元素獨立出來。
簡稱和縮寫都視為變量名、方法名和類名。以下名稱可讀性更強:
如何對待簡稱,JDK 和 Android 底層代碼存在很大的差異。因此,你幾乎不大可能與其它代碼取得一致。別無選擇,把簡稱當作完整的單詞看待吧。
關於本條規則的進一步解釋,請參閱 Effective Java 第 38 條和 Java Puzzlers 第 68條。
對那些臨時性的、短期的、夠棒但不完美的代碼,請使用 TODO 注釋。
TODO 注釋應該包含全部大寫的 TODO,後跟一個冒號:
// TODO: Remove this code after the UrlTable2 has been checked in. // TODO: Change this to use a flag instead of a constant.
如果 TODO 注釋是“將來要做某事”的格式,則請確保包含一個很明確的日期(“在2013 年 11 月會修正”),或是一個很明確的事件(“在所有代碼整合人員理解了 V7 協議之後刪除本段代碼”)。
記錄日志會對性能產生顯著的負面影響。如果日志內容不夠簡煉的話,很快會喪失可用性。日志功能支持五種不同的級別。以下列出了各個級別及其使用場合和方式。
注意:
在eclipse的preferences中,選擇java → code style → formatter中選擇Import,選擇工程根目錄下的development/ide/eclipse/目錄下的android-formatting.xml。
在eclipse的preferences中,選擇java → code style → Organize Imports中選擇Import,選擇工程根目錄下的development/ide/eclipse/目錄下的android.importorder。
說明:導入這兩個文件,是為了與源碼中的Android程序保持一致的編碼規范。android-formatting.xml用來配置eclipse編譯器的代碼風格;android.importorder用來配置eclipse的import的順序和結構。
微信公眾號是微信公眾平台下的一個小分支,有信息推廣推送的功能,公眾號每天定時的推送相關文章或者相關活動內容,讓用戶及時了解最新動態!那麼微信公眾號怎麼申請?
本文實例講述了Android使用ListView批量刪除item的方法。分享給大家供大家參考,具體如下:利用CheckBox選中一個或多個item,最後批量刪除它們。程序
很多時候Android常用的控件不能滿足我們的需求,那麼我們就需要自定義一個控件了。今天做了一個自定義控件的實例,來分享下。首先定義一個layout實現按鈕內部布局:&n
一般在本地進行OTA升級時,將升級包拷貝到SD卡,然後進入recovery模式選擇升級包進行升級,但不是很方便,於是做了一個小應用,通過調用RecoverySystem類
自己寫db文件方法有兩種:1、用sql server2005+sqlse