從這篇文章開始我們暫停一下對Android源碼的分析,開始講一下android產品研發中一些常用的技術,技巧,方法,實踐等姿勢。這裏需要強調的是我們所講解的這些東西可能對產品開發中比較常用的,因爲對於項目開發中,可能更多的強調管理,進度方法的東西,對工程化的東西比較強調,而我們這裏更多的是對產品技術方面的歸納總結。
而本文中選擇將開發規範作爲這個系列的第一篇文章,就是個人感覺產品研發過程中,開發規範真的很重要,很重要,非常重要(重要的事情說三遍),一個好的開發規範可以讓團隊中的人對他人的代碼更熟悉,新人也可以更好的瞭解產品的業務邏輯。開發規範並不是一個死的一成不變的,每個團隊可能都有自己的開發規範,只要是適合團隊的開發規範就是最好的開發規範。
所以本文中所講解的開發規範只能是拋磚引玉,有可取的地方可以借鑑,引用,不能照搬全抄不假思索,畢竟不同的團隊有不同的實際情況。最好的方式就是可以根據本文的開發規範總結出自身團隊比較適合的規範流程。
好吧,廢話不多說了,下面我們就介紹一下我在實踐中總結的android開發規範。
1 前言
1.1 爲什麼需要開發規範
編碼規範對於程序員而言尤爲重要,有以下幾個原因:
* 一個軟件的生命週期中,80%的花費在於維護
* 幾乎沒有任何一個軟件,在其整個生命週期中,均由最初的開發人員來維護
* 編碼規範可以改善軟件的可讀性,可以讓程序員儘快而徹底地理解新的代碼
* 如果你將源碼作爲產品發佈,就需要確任它是否被很好的打包並且清晰無誤,一如你已構建的其它任何產品
1.2 開發規範的作用
* 減少維護花費
* 提高可讀性
* 加快工作交接
* 減少名字增生
* 降低缺陷引入的機會
2 命名規範
2.1 常量命名規範
2.1.1 類型
常量命名規範
2.1.2 說明
常量用於保存需要常駐內存中並且經常使用變化不多的數據,定義常量的名稱的時候需要遵循望文知意的原則;
2.1.3 規則
全部爲大寫字母;
中間以“_”連接;
望文知意原則;
2.1.4 備註
代碼中涉及到直接使用某個字符串或者其他基本類型的值時,建議定義成常量,避免多處直接使用同樣的值作爲參數。
2.1.5 舉例
如:定義一個常量表示最小屏幕寬度的常量,則可以定義一個int類型的常量,該常量可以命名爲:“MIN_SCREEN_WIDTH“;
其他舉例:
例如:static final int MIN_SCREEN_WIDTH = 4;( √)
例如:static final int min_screen_width = 4;(×)
例如:static final int minScreenWidth = 4; (×)
例如:static final int WIDTH = 4;(×)
例如:static final int width = 4;(×)
例如:static final int wd = 4;(×)
2.2 變量命名規範
2.2.1 類型
變量命名規範
2.2.2 說明
變量用於保存系統中的臨時數據,變量命名時遵循望文知意,簡單明瞭,駝峯標示等原則。
2.2.3 規則
首字母大寫;
java駝峯命名;
望文知意原則;
推薦引用類型變量添加前綴“m”;
如果是View組件變量,則組件名稱爲xml文件中定義的ID名稱去掉下劃線,下劃線後一位大寫;
2.2.4 備註
無
2.2.5 舉例
如:定義一個表示最小屏幕寬度的變量,則可以定義一個int型的臨時變量爲:mMinScreenWidth;
例如:static final int mMinScreenWidth = 4; ( √)
例如:static final int minWidth = 4;(×)
例如:static final int screenWidth = 4;(×)
例如:static final int width = 4;(×)
例如:static final int min = 4; (×)
例如:static final int msw = 4; (×)
2.3 方法命名規範
2.3.1 類型
方法命名規範
2.3.2 說明
方法名的命名應該遵循簡單明瞭的原則;
2.3.3 規則
首字母小寫;
java駝峯命名;
簡單明瞭原則;
初始化View方法init*(每個init做一件事)
2.3.4 備註
同時在方法的實現上,儘量不要在一個方法中出現太多實現代碼,如一個方法有幾百行的實現邏輯,推薦在邏輯複雜時,按功能點拆分出多個方法,便於閱讀。
另外,出現功能一樣的實現邏輯,儘量抽取公用方法,避免將實現邏輯複製到多個用到的地方。
2.3.5 舉例
如:定義一個獲取屏幕寬度的方法,依照上述原則,則可以定義爲一個靜態方法:public static int getScreenWidth();
例如:public static int getScreenWidth();( √)
例如:public static int getscreenwidth();(×)
例如:public static int getScreenwidth();(×)
例如:public static int getWidth();(×)
例如:public static int getScreen();(×)
例如:public static int getSW();(×)
2.4 類命名規範
2.4.1 類型
類命名規範
2.4.2 說明
類名主要表示一個類的作用,需要簡明扼要,望文知意,並且首字母大寫。
2.4.3 規則
首字母大寫;
java駝峯命名;
望文知意原則;
能夠說明類的功能和主要作用(註釋的作用);
Acitivity類以Acitivity結尾;
Fragment類以Fragment結尾;
Service類以Service結尾;
BroadcastReceiver類以Receiver結尾;
ContentProvider類以Provider結尾;
Application類以Application結尾;
自定義View類以Custom**View結尾;
自定義Adapter類以Adapter結尾;
adapter中的ViewHolder以Holder結尾;
實體Bean以Model結尾;
2.4.4 備註
無
2.4.5 舉例
如:定義一個獲取屏幕信息的工具類,則可以定義爲public class ScreenUtils;
例如:public class ScreenUtils; ( √)
例如:public class Screenutils; (×)
例如:public class Screen; (×)
例如:public class screenutils; (×)
例如:public class screen; (×)
例如:public class su;(x)
2.5 接口命名規範
2.5.1 類型
接口命名規範
2.5.2 說明
接口命名需要簡單明瞭,長度不宜過長;
2.5.3 規則
首字母大寫(第二個字母也是大寫);
java駝峯命名;
望文知意原則;
建議在名稱前面追加“I”;
2.5.4 備註
I**Listener
I**CallBack
I**;
2.5.5 舉例
如:定義一個activity的方法接口,實現接口中的某些方法:public
interface IFunctionListener;
例如:public interface IFunctionListener;( √)
例如:public interface BaseActivity; (×)
例如:public interface Baseactivityinter; (×)
例如:public interface BaseInter; (×)
例如:public interface ActivityInter;(×)
2.6 包名規範
2.6.1 類型
包名規範
2.6.2 說明
用於分類管理類文件;
2.6.3 規則
所有字母小寫;
簡單明瞭,層級很深,沒有拼接的包名;
望文知意;
按功能劃分包名,如“我的”
工具類可以劃分爲一個工具類的包名,utils,裏面可以添加包名層級;
系統類的可以劃分爲一個系統類的包,system,裏面可以添加包名層級;
組件類的可以劃分爲一個組件類的包,*,裏面添加adapter的包名,自定義view包名;
Service類的可以劃分爲一個服務類的包,service,裏面可以添加包名層級;
數據庫相關類可以劃分爲一個數據庫類,db,裏面可以添加數據庫相關類,Bean類,數據庫服務類等;
廣播類的可以劃分爲廣播類的包,receiver,可以放一些廣播相關的類;
網絡類相關的可以劃分爲,network,放一些網絡相關的類;
Fragment類存放在fragment包下;
Activity類存放在Activity包下;
2.6.4 備註
無
2.6.5 舉例
無
2.7 目錄名稱規範
2.7.1 類型
目錄名稱規範
2.7.2 說明
主要是一些jar包,so文件的配置目錄名稱;
2.7.3 規則
全部爲小寫字母;
簡單明瞭;
望文知意;
駝峯表示;
2.7.4 備註
無
2.7.5 舉例
後期增加目錄的可能性不多,現列舉出系統中存在的目錄結構:
lib:第三方jar的保存路徑;
jniLibs:jni引用的so文件的目錄;
2.8 佈局文件名稱規範
2.8.1 類型
佈局文件名稱規範
2.8.2 說明
主要包含資源文件的命名問題;
2.8.3 規則
全部爲小寫字母;
中間以”_”連接;
望文知意原則;
佈局文件的開頭問類名;
列表項的xml佈局文件名稱:類名_item.xml;
activity類的xml文件名稱:類名_activity.xml;
fragment類的xml文件名稱:類名_fragment.xml;
自定義View的xml文件的名稱:類名_父類名.xml;
2.8.4 備註
無
2.8.5 舉例
如:如定義H5Activity的xml文件名稱,則可以定義爲h5.xml;儘量不使用大寫字母等。
2.9 drawable文件名稱規範
2.9.1 類型
drawable文件名稱命名規範
2.9.2 說明
主要包含資源文件的命名問題;
2.9.3 規則
全部爲小寫字母;
中間以”_”連接;
望文知意原則;
佈局文件的開頭問類名;
11_22_33_44,44:selector,shape(大概五六個,暫時不定義其他的); 33:src、bg、color(可擴展,可爲空); 22:狀態名稱或者爲空;11:業務名稱
2.9.4 備註
無
2.9.5 舉例
無
2.10 資源ID規範
2.10.1 類型
資源ID命名規範
2.10.2 說明
各種資源ID的定義問題;
2.10.3 規則
全部爲小寫字母;
中間以”_”連接;
望文知意原則;
2.10.4 備註
可以考慮按照組件的名稱的縮寫作爲前綴,(同一個xml文件中ID名稱不能重複)如:組件簡寫(大寫字母縮寫)_業務名稱
TextView的組件:tv_pay_money
Button的組件:btn_pay_money
EditText的組件:et_user_name
LinerLayout組件:ll_container
2.10.5 舉例
如:比如一個textview組件,可點擊用於支付的按鈕,則可以把ID定義爲: tv_pay_money;
3 註釋規範
3.1 類註釋
在類、接口定義之前當對其進行註釋,包括類、接口的目的、作用、功能、繼承於何種父類,實現的接口、實現的算法、使用方法、示例程序等。
/**
* author:作者
* time:時間
* desc:描述
*/
3.2 方法註釋
方法註釋的模板:
/**
* desc:描述
* @param 參數名 參數描述
* @param 參數名2 參數描述
* @return 返回值類型說明
* @throws Exception 異常說明
*/
3.3 類成員變量和常量註釋
成員變量和常量需要使用如下注釋的形式,註釋位於變量的上側;
/**
*
**/
3.4 內部邏輯註釋
內部邏輯註釋模板:
//支付成功
if (response.getRet() == 0) {
Toast.makeText(H5Activity.this, "支付成功", Toast.LENGTH_LONG).show();
goToNext(response);
}
//支付失敗
else if (response.getRet() == -1) {
Toast.makeText(H5Activity.this, "支付失敗", Toast.LENGTH_LONG).show();
//刷新當前頁面
reflush(currentUrl);
}
4 代碼順序
4.1 代碼順序
在一個典型的Activity中代碼的順序如下:
/**
* author:sh
* desc:該class的作用
* time:yyyy-MM-dd
**/
public class ClassName {
//(1) 成員變量集合
//(2) 回調方法集合
若該類爲activity,則:onCreate、**、onDestory;
若該類爲Fragment、則:onCreateView、**、onDestory;
//(3) 其他方法集合
}
5 代碼風格
5.1 大括號換行
左大括號不換行,右大括號換行;
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
5.2 小括號空格
if (condition) {
body();
} // 推薦
5.3 縮進
4 個空格作爲縮進排版的一個單位,不使用製表符 tab。
8 個空格作爲換行後的縮進,包括函數調用和賦值。
Instrument i =
someLongexpression_r(that, NotFit, on, one, line); // 推薦
5.4 每一行的長度
儘量避免一行的長度超過 100 個字符。
例外:如果註釋行包含了超過 100 個字符的命令示例或者 url 文字,爲了便於剪切和複製,其長度可以超過 100 個字符。
例外:import 行可以超過限制,因爲很少有人會去閱讀它。這也簡化了編程工具的寫入操作。
5.5 每次聲明一個變量
推薦一行一個聲明,因爲這樣以利於寫註釋;
int level; // indentation level
int size; // size of table
5.6 if-else語句
if-else語句應該具有如下格式:
if (condition) {
statements;
}
if (condition) {
statements;
} else {
statements;
}
if (condition) {
statements;
} else if (condition) {
statements;
} else{
statements;
}
注意:if語句總是用”{“和”}“括起來,避免使用如下容易引起錯誤的格式:
if (condition) // 避免
statement;
5.7 for語句
一個for語句應該具有如下格式:
for (initialization; condition; update) {
statements;
}
當在for語句的初始化或更新子句中使用逗號時,避免因使用三個以上變量,而導致複雜度提高。
若需要,可以在for循環之前(爲初始化子句)或for循環末尾(爲更新子句)使用單獨的語句。
5.8 while語句
一個while語句應該具有如下格式:
while (condition) {
statements;
}
5.9 do-while語句
do {
statements;
} while (condition);
5.10 switch語句
一個switch語句應該具有如下格式:
switch (condition) {
case ABC:
statements;
/* falls through */
case DEF:
statements;
break;
case XYZ:
statements;
break;
default:
statements;
break;
}
每當一個case順着往下執行時(因爲沒有break語句),通常應在break語句的位置添加註釋。
6 異常規範
6.1 異常名稱
定義異常的時候,異常的後綴名稱以Exception結尾,及**Exception;
6.2 異常描述
儘量英文描述,簡單明瞭;
6.3 異常格式
一個try-catch語句應該具有如下格式:
try {
statements;
} catch (ExceptionClass e) {
statements;
}
try {
statements;
} catch (ExceptionClass e) {
statements;
} finally {
statements;
}
7 其他規範
7.1 源文件的函數小於2K
一般來說源文件的行數不能大於2K行,過多的話可以考慮拆分功能,拆分函數等;
7.2 使用TODO註釋
對那些臨時性的、短期的、夠棒但不完美的代碼,請使用 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 註釋是“將來要做某事”的格式)。
7.3 使用自定義LOG
在系統中需要打印LOG的時候,儘量使用自定義的LOG,自定義的LOG在開發環境的時候會打印日誌,正式環境的時候不會打印日誌。
7.4 使用自定義TAG
在系統打印LOG的時候,使用TAG儘量使用tab,同意的TAG標誌。