前言
雖然我們項目的代碼時間并不長,也沒經(jīng)過太多人手扮授,但代碼的規(guī)范性依然堪憂芳室,目前存在較多的比較自由的「代碼規(guī)范」,這非常不利于項目的維護(hù)刹勃,代碼可讀性也不夠高堪侯,
此外,客戶端和后端的研發(fā)模式也完全不同荔仁,后端研發(fā)基本都是基于 SOA 思想的伍宦,通常一個子系統(tǒng) 3 個人一起維護(hù)就已經(jīng)是很充分的人力了,更多時候就是 1 個主力 + 1 個 backup 的人力配置乏梁。
而客戶端卻完全不同次洼,大家的代碼都是相互交叉的,一個模塊的代碼可能要經(jīng)歷數(shù)十人的蹂躪遇骑,所以形成一個一致的開發(fā)規(guī)范迫在眉睫卖毁。
為什么需要一致的代碼規(guī)范?
核心還是減少溝通成本落萎,提升我們的 Code Review 效率亥啦,讓我們的代碼更加易于維護(hù)炭剪。此外,一個一致的代碼規(guī)范可以造成更少的 bug禁悠,也就意味著更節(jié)省時間和金錢。
當(dāng)然兑宇,規(guī)范是約定的碍侦,本系列文字全是筆者多年來博采眾長,積累而成隶糕,所以有任何不同意見瓷产,歡迎評論拍磚。
1. Android 的工具規(guī)范
工欲善其事枚驻,必先利其器濒旦。
由于 Android 基本都基于 Android Studio 進(jìn)行開發(fā),所以工具規(guī)范全部以 Android Studio 為前提再登。
- 必須使用最新的穩(wěn)定版本的 Android Studio 進(jìn)行開發(fā)尔邓;
- 編碼格式必須統(tǒng)一為 UTF-8;
-
刪除多余的 import锉矢,減少警告出現(xiàn)梯嗽,可利用 AS 的 Optimize Imports(Settings -> Keymap -> Optimize Imports)快捷鍵,設(shè)置自己的喜好沽损。
- 編輯完 .java灯节、.kt、.xml 等文件后必須格式化(需要在設(shè)置好以下幾點的前提下)
Reformat Code 的必要性绵估,一定需要保證 IDE 配置一致為前提炎疆,盡可能貼切于 Android Studio 默認(rèn)。
強(qiáng)烈建議對于比較長的老代碼局部格式化国裳,不全局格式化
-
每行字符數(shù)不得超過 160 字符形入,設(shè)置 Editor -> Code Style
-
全部設(shè)置為單路徑引用,
kotlinx.android.synthetic.main
除外缝左。
Java Code Style
以上幾處設(shè)置完畢唯笙,其他采用 Android Studio 默認(rèn)方式,再進(jìn)行 Reformat Code 快捷鍵即可盒使。
2. Android 的分包規(guī)范
前面強(qiáng)調(diào)了工具的統(tǒng)一配置崩掘,再利用 Android Studio 本身的功能便可把代碼風(fēng)格變得一致。接下來就帶來第二部分:Android 的分包規(guī)范少办。
對于分包苞慢,我們需要達(dá)成一致,我們采用 PBF 方式英妓,不推薦使用 PBL 方式挽放。
PBF(按功能分包 Package By Feature)
PBL(按層分包 Package By Layer)
PBF 可能不是很好區(qū)分在哪個功能中绍赛,不過也比 PBL 要好找很多,且 PBF 與 PBL 相比較有如下優(yōu)勢:
package 內(nèi)高內(nèi)聚辑畦,package 間低耦合
哪塊要添新功能吗蚌,只改某一個 package 下的東西,而PBL 需要改多個 package纯出,非常麻煩蚯妇。package 有私有作用域(package-private scope)
原則上一個 package 下的不允許其他類訪問都是不應(yīng)該加上 public 的。很容易刪除功能
統(tǒng)計發(fā)現(xiàn)新功能沒人用暂筝,這個版本那塊功能得去掉箩言。如果是 PBL,得從功能入口到整個業(yè)務(wù)流程把受到牽連的所有能刪的代碼和 class 都揪出來刪掉焕襟,一不小心就完蛋陨收。如果是 PBF,好說鸵赖,先刪掉對應(yīng)包务漩,再刪掉功能入口(刪掉包后入口肯定報錯了),完事它褪。高度抽象
解決問題的一般方法是從抽象到具體菲饼,PBF 包名是對功能模塊的抽象,包內(nèi)的 class 是實現(xiàn)細(xì)節(jié)列赎,符合從抽象到具體宏悦,而 PBL 弄反了。PBF 從確定 AppName 開始包吝,根據(jù)功能模塊劃分 package饼煞,再考慮每塊的具體實現(xiàn)細(xì)節(jié),而 PBL 從一開始就要考慮要不要 dao 層诗越,要不要 com 層等等砖瞧。只通過 class 來分離邏輯代碼
PBL 既分離 class 又分離 package,而 PBF 只通過 class 來分離邏輯代碼嚷狞。package 的大小有意義了
PBL 中包的大小無限增長是合理的块促,因為功能越添越多,而 PBF 中包太大(包里 class 太多)表示這塊需要重構(gòu)(劃分子包)床未。
3. Android 的命名規(guī)范
代碼中的命名嚴(yán)禁使用拼音與英文混合的方式竭翠,更不允許直接使用中文的方式。正確的英文拼寫和語法可以讓閱讀者易于理解薇搁,避免歧義斋扰。
注意:即使純拼音命名方式也要避免采用。但國際通用的名稱,可視同英文传货,比如
toutiao
屎鳍、douyin
等。
3.1 包名
Android 里面有 package 的概念问裕,所以需要約定一下包名命名規(guī)范逮壁。
包名全部小寫,不允許出現(xiàn)中文粮宛、大寫字母或者下劃線窥淆,前面為子模塊命名,再根據(jù) PBF 方式進(jìn)行命名窟勃。
3.2 類名
類名都以 UpperCamelCase
風(fēng)格編寫祖乳。
類名通常是名詞或名詞短語逗堵,接口名稱有時可能是形容詞或形容詞短語”酰現(xiàn)在還沒有特定的規(guī)則或行之有效的約定來命名注解類型。
名詞蜒秤,采用大駝峰命名法汁咏,盡量避免縮寫,除非該縮寫是眾所周知的作媚, 比如 HTML攘滩、URL,如果類名稱中包含單詞縮寫纸泡,則單詞縮寫的每個字母均應(yīng)大寫漂问。
類 | 描述 | 例如 |
---|---|---|
Activity 類 |
模塊名 + Activity
|
閃屏頁類 SplashActivity
|
Fragment 類 |
模塊名 + Fragment
|
主頁類 HomeFragment
|
Service 類 |
模塊名 + Service
|
時間服務(wù) TimeService
|
BroadcastReceiver 類 |
功能名 + Receiver
|
推送接收 JPushReceiver
|
ContentProvider 類 |
功能名 + Provider
|
ShareProvider |
自定義 View | 功能名 + View/ViewGroup(組件名稱) | ShapeButton |
Dialog對話框 | 功能名+Dialog | ImagePickerDialog |
Adapter 類 |
模塊名 + Adapter
|
課程詳情適配器 LessonDetailAdapter
|
解析類 | 功能名 + Parser
|
首頁解析類 HomePosterParser
|
工具方法類 | 功能名 + Utils 或 Manager
|
線程池管理類:ThreadPoolManager 日志工具類: LogUtils (Logger 也可)打印工具類: PrinterUtils
|
數(shù)據(jù)庫類 | 功能名 + DBHelper
|
新聞數(shù)據(jù)庫:NewsDBHelper
|
自定義的共享基礎(chǔ)類 |
Base + 基礎(chǔ) |
BaseActivity , BaseFragment
|
抽象類 |
Base / Abstract 開頭 |
AbstractLogin |
異常類 |
Exception 結(jié)尾 |
LoginException |
接口 |
able / ible 結(jié)尾 / I 開頭 |
Runnable , Accessible ,ILoginView
|
測試類的命名以它要測試的類的名稱開始女揭,以 Test 結(jié)束蚤假。例如:HashTest
或 HashIntegrationTest
。
接口(interface):命名規(guī)則與類一樣采用大駝峰命名法吧兔,多以 able 或 ible 結(jié)尾磷仰,如 interface Runnable
、interface Accessible
境蔼。
注意:如果項目采用 MVP灶平,所有 Model、View箍土、Presenter 的接口都以 I 為前綴逢享,不加后綴,其他的接口采用上述命名規(guī)則吴藻。
3.3 方法名
方法名都以 lowerCamelCase
風(fēng)格編寫拼苍。
方法名通常是動詞或動詞短語。
方法 | 說明 |
---|---|
initXX() |
初始化相關(guān)方法,使用 init 為前綴標(biāo)識疮鲫,如初始化布局 initView()
|
isXX() , checkXX()
|
方法返回值為 boolean 型的請使用 is/check 為前綴標(biāo)識 |
getXX() |
返回某個值的方法吆你,使用 get 為前綴標(biāo)識 |
setXX() |
設(shè)置某個屬性值 |
handleXX() , processXX()
|
對數(shù)據(jù)進(jìn)行處理的方法 |
displayXX() , showXX()
|
彈出提示框和提示信息,使用 display/show 為前綴標(biāo)識 |
updateXX() |
更新數(shù)據(jù) |
saveXX() , insertXX()
|
保存或插入數(shù)據(jù) |
resetXX() |
重置數(shù)據(jù) |
clearXX() |
清除數(shù)據(jù) |
removeXX() , deleteXX()
|
移除數(shù)據(jù)或者視圖等俊犯,如 removeView()
|
drawXX() |
繪制數(shù)據(jù)或效果相關(guān)的妇多,使用 draw 前綴標(biāo)識 |
3.4 變量命名
這里的變量為廣義的變量,包括了常量燕侠、局部變量者祖、全局變量等,它們的基礎(chǔ)規(guī)則是:
- 類型需要是名詞 / 名詞短語绢彤;
- 采用
lowerCamelCase
風(fēng)格七问;
在具體的變量命名時,會根據(jù)該變量的類型不同而附加額外的命名規(guī)則:
類型 | 說明 | 例如 |
---|---|---|
常量 | 大寫 & 下劃線隔開茫舶,Kotlin 一定要 const val |
const val TYPE_NORMAL = 1 static final TYPE_NORMAL = 1
|
臨時變量名 | 整型:i 械巡、j 、k 饶氏、m 讥耗、n ,字符型一般用 c 疹启、d 古程、e
|
for(int i = 0;i < len; i++) |
其他變量 |
lowerCamelCase 風(fēng)格即可,私有變量也不要使用 m 開頭 |
private int tmp; |
Kotlin | 只讀變量使用 val 喊崖,可變變量使用 var 挣磨,盡可能使用 val
|
var tmp = 0 val defaultIndex = 0
|
3.5 資源命名
Android 的資源包括:
資源文件命名為全部小寫,采用下劃線命名法荤懂。
3.5.1 動畫資源文件(anim/ 和 animator/)
安卓主要包含屬性動畫和視圖動畫茁裙,其視圖動畫包括補(bǔ)間動畫和逐幀動畫。屬性動畫文件需要放在 res/animator/
目錄下势誊,視圖動畫文件需放在 res/anim/
目錄下呜达。命名規(guī)則:{模塊名_}邏輯名稱
。
說明:
{}
中的內(nèi)容為可選粟耻,邏輯名稱
可由多個單詞加下劃線組成查近。例如:refresh_progress.xml
、market_cart_add.xml
挤忙、market_cart_remove.xml
霜威。
如果是普通的補(bǔ)間動畫或者屬性動畫,可采用:動畫類型_方向
的命名方式册烈。
例如:
名稱 | 說明 |
---|---|
fade_in |
淡入 |
fade_out |
淡出 |
push_down_in |
從下方推入 |
push_down_out |
從下方推出 |
push_left |
推向左方 |
slide_in_from_top |
從頭部滑動進(jìn)入 |
zoom_enter |
變形進(jìn)入 |
slide_in |
滑動進(jìn)入 |
shrink_to_middle |
中間縮小 |
3.5.2 顏色資源文件(color/)
color/ 是專門用于存放顏色相關(guān)資源的文件夾戈泼。命名規(guī)則:類型{_模塊名}_邏輯名稱
婿禽。
說明:
{}
中的內(nèi)容為可選。例如:sel_btn_font.xml
大猛。
顏色資源也可以放于 res/drawable/
目錄扭倾,引用時則用 @drawable
來引用,但不推薦這么做挽绩,最好還是把兩者分開膛壹。
3.5.3 圖片資源文件(drawable/ 和 mipmap/)
res/drawable/
目錄下放的是位圖文件(.png、.9.png唉堪、.jpg模聋、.gif)或編譯為可繪制對象資源子類型的 XML 文件,而 res/mipmap/
目錄下放的是不同密度的啟動圖標(biāo)唠亚,所以 res/mipmap/
只用于存放啟動圖標(biāo)链方,其余圖片資源文件都應(yīng)該放到 res/drawable/
目錄下。
命名規(guī)則:類型{_模塊名}_邏輯名稱
灶搜、類型{_模塊名}_顏色
祟蚀。
說明:
{}
中的內(nèi)容為可選;類型
可以是可繪制對象資源類型占调,也可以是控件類型最后可加后綴_small
表示小圖暂题,_big
表示大圖移剪。
例如:
名稱 | 說明 |
---|---|
btn_main_about.png |
主頁關(guān)于按鍵 類型_模塊名_邏輯名稱
|
btn_back.png |
返回按鍵 類型_邏輯名稱
|
divider_maket_white.png |
商城白色分割線 類型_模塊名_顏色
|
ic_edit.png |
編輯圖標(biāo) 類型_邏輯名稱
|
bg_main.png |
主頁背景 類型_邏輯名稱
|
btn_red.png |
紅色按鍵 類型_顏色
|
btn_red_big.png |
紅色大按鍵 類型_顏色
|
ic_avatar_small.png |
小頭像圖標(biāo) 類型_邏輯名稱
|
bg_input.png |
輸入框背景 類型_邏輯名稱
|
divider_white.png |
白色分割線 類型_顏色
|
bg_main_head.png |
主頁頭部背景 類型_模塊名_邏輯名稱
|
def_search_cell.png |
搜索頁面默認(rèn)單元圖片 類型_模塊名_邏輯名稱
|
ic_more_help.png |
更多幫助圖標(biāo) 類型_邏輯名稱
|
divider_list_line.png |
列表分割線 類型_邏輯名稱
|
sel_search_ok.xml |
搜索界面確認(rèn)選擇器 類型_模塊名_邏輯名稱
|
shape_music_ring.xml |
音樂界面環(huán)形形狀 類型_模塊名_邏輯名稱
|
如果有多種形態(tài)究珊,如按鈕選擇器:sel_btn_xx.xml
,采用如下命名:
名稱 | 說明 |
---|---|
sel_btn_xx |
作用在 btn_xx 上的 selector
|
btn_xx_normal |
默認(rèn)狀態(tài)效果 |
btn_xx_pressed |
state_pressed 點擊效果 |
btn_xx_focused |
state_focused 聚焦效果 |
btn_xx_disabled |
state_enabled 不可用效果 |
btn_xx_checked |
state_checked 選中效果 |
btn_xx_selected |
state_selected 選中效果 |
btn_xx_hovered |
state_hovered 懸停效果 |
btn_xx_checkable |
state_checkable 可選效果 |
btn_xx_activated |
state_activated 激活效果 |
btn_xx_window_focused |
state_window_focused 窗口聚焦效果 |
注意:使用 Android Studio 的插件 SelectorChapek 可以快速生成 selector纵苛,前提是命名要規(guī)范剿涮。
3.5.4 布局資源文件(layout/)
命名規(guī)則:類型_模塊名
、{模塊名_}類型_邏輯名稱
攻人。(也采用 PBF取试,方便查看,尤其在大項目中)
說明:
{}
中的內(nèi)容為可選怀吻。
例如:
類型 | 名稱 | 說明 |
---|---|---|
Activity |
main_activity.xml |
主窗體 模塊名_類型
|
Fragment |
music_fragment.xml |
音樂片段 模塊名_類型
|
Dialog |
loading_dialog.xml |
加載對話框 邏輯名稱_類型
|
PopupWindow |
info_ppw.xml |
信息彈窗(PopupWindow) 邏輯名稱_類型
|
adapter 的列表項 |
main_song_item.xml |
主頁歌曲列表項 模塊名_類型_邏輯名稱
|
3.5.5 布局資源 id 命名
命名規(guī)則:{模塊名_}_邏輯名_view 縮寫(功能)
瞬浓,例如: main_search_btn
、back_btn
蓬坡。此外猿棉,采用 Kotlinx 直接獲取布局文件的時候,id 命名采用駝峰樣式屑咳。
說明:
{}
中的內(nèi)容為可選萨赁。參考 GoogleSamples Demo:https://github.com/android/architecture-samples
例如:
類型 | 規(guī)范 | 命名示例 |
---|---|---|
TextView |
xxx_text |
user_login_text |
EditText |
xxx_edit |
user_login_edit |
ImageView |
xxx_iv |
user_login_iv |
Button |
xxx_btn |
user_login_btn |
CheckBox |
xxx_cb |
user_login_cb |
GridView |
xxx_gv |
user_login_gv |
ListView |
xxx_lv |
user_login_lv |
RecyclerView |
xxx_rv |
user_login_rv |
RadioButton |
xxx_rb |
user_login_rb |
LinearLayout |
xxx_ll |
user_login_ll |
RelativeLayout |
xxx_rl |
user_login_rl |
FrameLayout |
xxx_fl |
user_login_fl |
GridLayout |
xxx_gl |
user_login_gl |
ConstraintLayout |
xxx_cl |
user_login_cl |
3.5.6 菜單資源文件(menu/)
菜單相關(guān)的資源文件應(yīng)放在該目錄下。命名規(guī)則:{模塊名_}邏輯名稱
說明:
{}
中的內(nèi)容為可選兆龙。例如:main_drawer.xml
杖爽、navigation.xml
。
3.5.7 colors.xml
<color>
的 name
命名使用下劃線命名法,在你的 colors.xml
文件中應(yīng)該只是映射顏色的名稱一個 ARGB 值慰安,而沒有其它的腋寨。不要使用它為不同的按鈕來定義 ARGB 值。
例如化焕,不要像下面這樣做:
<resources>
<color name="button_foreground">#FFFFFF</color>
<color name="button_background">#2A91BD</color>
<color name="comment_background_inactive">#5F5F5F</color>
<color name="comment_background_active">#939393</color>
<color name="comment_foreground">#FFFFFF</color>
<color name="comment_foreground_important">#FF9D2F</color>
...
<color name="comment_shadow">#323232</color>
使用這種格式精置,會非常容易重復(fù)定義 ARGB 值,而且如果應(yīng)用要改變基色的話會非常困難锣杂。同時脂倦,這些定義是跟一些環(huán)境關(guān)聯(lián)起來的,如 button
或者 comment
元莫,應(yīng)該放到一個按鈕風(fēng)格中赖阻,而不是在 colors.xml
文件中。
相反踱蠢,應(yīng)該這樣做:
<resources>
<!-- grayscale -->
<color name="white" >#FFFFFF</color>
<color name="gray_light">#DBDBDB</color>
<color name="gray" >#939393</color>
<color name="gray_dark" >#5F5F5F</color>
<color name="black" >#323232</color>
<!-- basic colors -->
<color name="green">#27D34D</color>
<color name="blue">#2A91BD</color>
<color name="orange">#FF9D2F</color>
<color name="red">#FF432F</color>
</resources>
向應(yīng)用設(shè)計者那里要這個調(diào)色板火欧,名稱不需要跟 "green"
、"blue"
等等相同茎截。"brand_primary"
苇侵、"brand_secondary"
、"brand_negative"
這樣的名字也是完全可以接受的企锌。像這樣規(guī)范的顏色很容易修改或重構(gòu)榆浓,會使應(yīng)用一共使用了多少種不同的顏色變得非常清晰。通常一個具有審美價值的 UI 來說撕攒,減少使用顏色的種類是非常重要的陡鹃。
注意:如果某些顏色和主題有關(guān),那就單獨寫一個
colors_theme.xml
抖坪。
3.5.8 strings.xml
<string>
的 name
命名使用下劃線命名法萍鲸,采用以下規(guī)則:{模塊名_}邏輯名稱
,這樣方便同一個界面的所有 string
都放到一起擦俐,方便查找脊阴。
名稱 | 說明 |
---|---|
main_menu_about |
主菜單按鍵文字 |
friend_title |
好友模塊標(biāo)題欄 |
friend_dialog_del |
好友刪除提示 |
login_check_email |
登錄驗證 |
dialog_title |
彈出框標(biāo)題 |
button_ok |
確認(rèn)鍵 |
loading |
加載文字 |
3.5.9 styles.xml
<style>
的 name
命名使用大駝峰命名法,幾乎每個項目都需要適當(dāng)?shù)氖褂?styles.xml
文件蚯瞧,因為對于一個視圖來說嘿期,有一個重復(fù)的外觀是很常見的,將所有的外觀細(xì)節(jié)屬性(colors
状知、padding
秽五、font
)放在 styles.xml
文件中。 在應(yīng)用中對于大多數(shù)文本內(nèi)容饥悴,最起碼你應(yīng)該有一個通用的 styles.xml
文件坦喘,例如:
<style name="ContentText">
<item name="android:textSize">@dimen/font_normal</item>
<item name="android:textColor">@color/basic_black</item>
</style>
應(yīng)用到 TextView
中:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/price"
style="@style/ContentText"/>
或許你需要為按鈕控件做同樣的事情盲再,不要停止在那里,將一組相關(guān)的和重復(fù) android:xxxx
的屬性放到一個通用的 <style>
中瓣铣。
4. Android 的注釋規(guī)范
4.1 類注釋
每個類完成后應(yīng)該有作者姓名和聯(lián)系方式的注釋答朋,對自己的代碼負(fù)責(zé)。
/**
* <pre>
* author : nanchen
* e-mail : xxx@xx
* time : 2021/01/18
* desc : xxxx 描述
* version: 1.0
* </pre>
*/
public class WelcomeActivity {
...
}
具體可以在 AS 中自己配制棠笑,進(jìn)入 Settings -> Editor -> File and Code Templates -> Includes -> File Header梦碗,輸入
/**
* <pre>
* author : ${USER}
* e-mail : xxx@xx
* time : ${YEAR}/${MONTH}/${DAY}
* desc :
* version: 1.0
* </pre>
*/
這樣便可在每次新建類的時候自動加上該頭注釋。
4.2 方法注釋
每一個成員方法(包括自定義成員方法、覆蓋方法、屬性方法)的方法頭都必須做方法頭注釋刽宪,在方法前一行輸入 /** + 回車
或者設(shè)置 Fix doc comment
(Settings -> Keymap -> Fix doc comment)快捷鍵亥宿,AS 便會幫你生成模板诊霹,我們只需要補(bǔ)全參數(shù)即可,如下所示。@param
, @return
, @throws
, @deprecated
這 4 種標(biāo)記出現(xiàn)的時候,描述都不能為空念赶。當(dāng)描述無法在一行中容納,連續(xù)行至少需要再縮進(jìn) 4 個空格恰力。
/**
* Report an accessibility action to this view's parents for delegated processing.
*
* <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally
* call this method to delegate an accessibility action to a supporting parent. If the parent
* returns true from its
* {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)}
* method this method will return true to signify that the action was consumed.</p>
*
* <p>This method is useful for implementing nested scrolling child views. If
* {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action
* a custom view implementation may invoke this method to allow a parent to consume the
* scroll first. If this method returns true the custom view should skip its own scrolling
* behavior.</p>
*
* @param action Accessibility action to delegate
* @param arguments Optional action arguments
* @return true if the action was consumed by a parent
*/
public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) {
for (ViewParent p = getParent(); p != null; p = p.getParent()) {
if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) {
return true;
}
}
return false;
}
4.3 塊注釋
塊注釋與其周圍的代碼在同一縮進(jìn)級別叉谜。它們可以是 /* ... */
風(fēng)格,也可以是 // ...
風(fēng)格(//
后最好帶一個空格)踩萎。對于多行的 /* ... */
注釋停局,后續(xù)行必須從 *
開始, 并且與前一行的 *
對齊驻民。以下示例注釋都是 OK 的翻具。
/*
* This is okay.
*/
// And so
// is this.
/* Or you can
* even do this. */
注釋不要封閉在由星號或其它字符繪制的框架里履怯。
Tip:在寫多行注釋時回还,如果你希望在必要時能重新?lián)Q行(即注釋像段落風(fēng)格一樣),那么使用
/* ... */
叹洲。
比如:
4.4 全局變量的注釋
全局變量的注釋樣式如下(注意注釋之間有空格):
/**
* The next available accessibility id.
*/
private static int nextAccessibilityViewId;
/**
* The animation currently associated with this view.
*/
protected Animation currentAnimation = null;
4.5 其他一些注釋
AS 已幫你集成了一些注釋模板柠硕,我們只需要直接使用即可,在代碼中輸入 TODO
运提、FIXME
等這些注釋模板蝗柔,回車后便會出現(xiàn)如下注釋。
// TODO: 17/3/14 需要實現(xiàn)民泵,但目前還未實現(xiàn)的功能的說明
// FIXME: 17/3/14 需要修正癣丧,甚至代碼是錯誤的,不能工作栈妆,需要修復(fù)的說明
4.5 注釋必須遵守的規(guī)范
4.5.1 不言自明的方法不要加注釋胁编。
比如 Item getItem(int index)
是一段自說明的代碼厢钧,我們可以直接從方法的命名就能知道它是干嘛的,所以不需要增加注釋嬉橙。
4.5.2 提測的代碼不應(yīng)該有 TODO 這樣的注釋
5. 代碼樣式規(guī)范
5.1 使用標(biāo)準(zhǔn)大括號樣式
左大括號不單獨占一行早直,與其前面的代碼位于同一行:
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
我們需要在條件語句周圍添加大括號。例外情況:如果整個條件語句(條件和主體)適合放在同一行市框,那么您可以(但不是必須)將其全部放在一行上霞扬。例如,我們接受以下樣式:
if (condition) {
body();
}
同樣也接受以下樣式:
if (condition) body();
但不接受以下樣式:
if (condition)
body(); // bad!
5.2 編寫簡短方法
在可行的情況下枫振,盡量編寫短小精煉的方法喻圃。我們了解,有些情況下較長的方法是恰當(dāng)?shù)姆嗦耍虼藢Ψ椒ǖ拇a長度沒有做出硬性限制级及。如果某個方法的代碼超出 40 行,請考慮是否可以在不破壞程序結(jié)構(gòu)的前提下對其拆解额衙。
5.3 類成員的順序
這并沒有唯一的正確解決方案饮焦,但如果都使用一致的順序?qū)岣叽a的可讀性,推薦使用如下排序:
- 常量(Kotlin 伴生對象放在開頭)
- 字段
- 構(gòu)造函數(shù)
- 重寫函數(shù)和回調(diào)
- 公有函數(shù)
- 私有函數(shù)
- 內(nèi)部類或接口
例如:
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private String mTitle;
private TextView mTextViewTitle;
@Override
public void onCreate() {
...
}
public void setTitle(String title) {
mTitle = title;
}
private void setUpView() {
...
}
static class AnInnerClass {
}
}
如果類繼承于 Android 組件(例如 Activity
或 Fragment
)窍侧,那么把重寫函數(shù)按照他們的生命周期進(jìn)行排序是一個非常好的習(xí)慣县踢,例如,Activity
實現(xiàn)了 onCreate()
伟件、onDestroy()
硼啤、onPause()
、onResume()
斧账,它的正確排序如下所示:
public class MainActivity extends Activity {
//Order matches Activity lifecycle
@Override
public void onCreate() {}
@Override
public void onResume() {}
@Override
public void onPause() {}
@Override
public void onDestroy() {}
}
5.4 函數(shù)參數(shù)的排序
在 Android 開發(fā)過程中谴返,Context
在函數(shù)參數(shù)中是再常見不過的了,我們最好把 Context
作為其第一個參數(shù)咧织。
正相反嗓袱,我們把回調(diào)接口應(yīng)該作為其最后一個參數(shù)。
例如:
// Context always goes first
public User loadUser(Context context, int userId);
// Callbacks always go last
public void loadUserAsync(Context context, int userId, UserCallback callback);
5.5 字符串常量的命名和值
Android SDK 中的很多類都用到了鍵值對函數(shù)习绢,比如 SharedPreferences
渠抹、Bundle
、Intent
闪萄,所以梧却,即便是一個小應(yīng)用,我們最終也不得不編寫大量的字符串常量败去。
當(dāng)時用到這些類的時候放航,我們 必須 將它們的鍵定義為 static final
字段,并遵循以下指示作為前綴圆裕。
類 | 字段名前綴 |
---|---|
SharedPreferences | PREF_ |
Bundle | BUNDLE_ |
Fragment Arguments | ARGUMENT_ |
Intent Extra | EXTRA_ |
Intent Action | ACTION_ |
說明:雖然 Fragment.getArguments()
得到的也是 Bundle
广鳍,但因為這是 Bundle
的常用用法缺菌,所以特意為此定義一個不同的前綴。
例如:
// 注意:字段的值與名稱相同以避免重復(fù)問題
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";
// 與意圖相關(guān)的項使用完整的包名作為值的前綴
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
5.6 行長限制
代碼中每一行文本的長度都應(yīng)該不超過 160 個字符搜锰。雖然關(guān)于此規(guī)則存在很多爭論伴郁,但最終決定仍是以 160 個字符為上限,如果行長超過了 160(AS 窗口右側(cè)的豎線就是設(shè)置的行寬末尾 )蛋叼,我們通常有兩種方法來縮減行長焊傅。
- 提取一個局部變量或方法(最好)。
- 使用換行符將一行換成多行狈涮。
不過存在以下例外情況:
- 如果備注行包含長度超過 160 個字符的示例命令或文字網(wǎng)址狐胎,那么為了便于剪切和粘貼,該行可以超過 160 個字符歌馍。
- 導(dǎo)入語句行可以超出此限制握巢,因為用戶很少會看到它們(這也簡化了工具編寫流程)。
5.6.1 換行策略
這沒有一個準(zhǔn)確的解決方案來決定如何換行松却,通常不同的解決方案都是有效的暴浦,但是有一些規(guī)則可以應(yīng)用于常見的情況。
5.6.1.1 操作符的換行
除賦值操作符之外晓锻,我們把換行符放在操作符之前歌焦,例如:
int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne
+ theFinalOne;
賦值操作符的換行我們放在其后,例如:
int longName =
anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;
5.6.1.2 函數(shù)鏈的換行
當(dāng)同一行中調(diào)用多個函數(shù)時(比如使用構(gòu)建器時)砚哆,對每個函數(shù)的調(diào)用應(yīng)該在新的一行中独撇,我們把換行符插入在 .
之前。
例如:
Picasso.with(context).load("https://blankj.com/images/avatar.jpg").into(ivAvatar);
我們應(yīng)該使用如下規(guī)則:
Picasso.with(context)
.load("https://blankj.com/images/avatar.jpg")
.into(ivAvatar);
5.6.1.3 多參數(shù)的換行
當(dāng)一個方法有很多參數(shù)或者參數(shù)很長的時候躁锁,我們應(yīng)該在每個 ,
后面進(jìn)行換行纷铣。
比如:
loadPicture(context, "https://blankj.com/images/avatar.jpg", ivAvatar, "Avatar of the user", clickListener);
我們應(yīng)該使用如下規(guī)則:
loadPicture(context,
"https://blankj.com/images/avatar.jpg",
ivAvatar,
"Avatar of the user",
clickListener);
5.6.1.4 RxJava 鏈?zhǔn)降膿Q行
RxJava 的每個操作符都需要換新行,并且把換行符插入在 .
之前搜立。
例如:
public Observable<Location> syncLocations() {
return mDatabaseHelper.getAllLocations()
.concatMap(new Func1<Location, Observable<? extends Location>>() {
@Override
public Observable<? extends Location> call(Location location) {
return mRetrofitService.getLocation(location.id);
}
})
.retry(new Func2<Integer, Throwable, Boolean>() {
@Override
public Boolean call(Integer numRetries, Throwable throwable) {
return throwable instanceof RetrofitError;
}
});
}
參考文檔:
https://source.android.com/source/code-style?hl=zh-cn
https://developer.android.com/kotlin/style-guide?hl=zh-cn
https://github.com/Blankj/AndroidStandardDevelop