前言
雖然我們專案的程式碼時間並不長,也沒經過太多人手,但程式碼的規範性依然堪憂,目前存在較多的比較自由的「程式碼規範」,這非常不利於專案的維護,程式碼可讀性也不夠高,
此外,客戶端和後端的研發模式也完全不同,後端研發基本都是基於 SOA 思想的,通常一個子系統 3 個人一起維護就已經是很充分的人力了,更多時候就是 1 個主力 + 1 個 backup 的人力配置。
而客戶端卻完全不同,大家的程式碼都是相互交叉的,一個模組的程式碼可能要經歷數十人的蹂躪,所以形成一個一致的開發規範迫在眉睫。
為什麼需要一致的程式碼規範?
核心還是減少溝通成本,提升我們的 Code Review 效率,讓我們的程式碼更加易於維護。此外,一個一致的程式碼規範可以造成更少的 bug,也就意味著更節省時間和金錢。
當然,規範是約定的,本系列文字全是筆者多年來博採眾長,積累而成,所以有任何不同意見,歡迎評論拍磚。
1. Android 的工具規範
工欲善其事,必先利其器。
由於 Android 基本都基於 Android Studio 進行開發,所以工具規範全部以 Android Studio 為前提。
- 必須使用最新的穩定版本的 Android Studio 進行開發;
- 編碼格式必須統一為 UTF-8;
- 刪除多餘的 import,減少警告出現,可利用 AS 的 Optimize Imports(Settings -> Keymap -> Optimize Imports)快捷鍵,設定自己的喜好。
- 編輯完 .java、.kt、.xml 等檔案後必須格式化(需要在設定好以下幾點的前提下)
Reformat Code 的必要性,一定需要保證 IDE 配置一致為前提,儘可能貼切於 Android Studio 預設。
強烈建議對於比較長的老程式碼區域性格式化,不全域性格式化
-
每行字元數不得超過 160 字元,設定 Editor -> Code Style
-
全部設定為單路徑引用,
kotlinx.android.synthetic.main
除外。
以上幾處設定完畢,其他採用 Android Studio 預設方式,再進行 Reformat Code 快捷鍵即可。
2. Android 的分包規範
前面強調了工具的統一配置,再利用 Android Studio 本身的功能便可把程式碼風格變得一致。接下來就帶來第二部分:Android 的分包規範。
對於分包,我們需要達成一致,我們採用 PBF 方式,不推薦使用 PBL 方式。
PBF(按功能分包 Package By Feature)
PBL(按層分包 Package By Layer)
PBF 可能不是很好區分在哪個功能中,不過也比 PBL 要好找很多,且 PBF 與 PBL 相比較有如下優勢:
-
package 內高內聚,package 間低耦合
哪塊要添新功能,只改某一個 package 下的東西,而PBL 需要改多個 package,非常麻煩。 -
package 有私有作用域(package-private scope)
原則上一個 package 下的不允許其他類訪問都是不應該加上 public 的。 -
很容易刪除功能
統計發現新功能沒人用,這個版本那塊功能得去掉。如果是 PBL,得從功能入口到整個業務流程把受到牽連的所有能刪的程式碼和 class 都揪出來刪掉,一不小心就完蛋。如果是 PBF,好說,先刪掉對應包,再刪掉功能入口(刪掉包後入口肯定報錯了),完事。 -
高度抽象
解決問題的一般方法是從抽象到具體,PBF 包名是對功能模組的抽象,包內的 class 是實現細節,符合從抽象到具體,而 PBL 弄反了。PBF 從確定 AppName 開始,根據功能模組劃分 package,再考慮每塊的具體實現細節,而 PBL 從一開始就要考慮要不要 dao 層,要不要 com 層等等。 -
只通過 class 來分離邏輯程式碼
PBL 既分離 class 又分離 package,而 PBF 只通過 class 來分離邏輯程式碼。 -
package 的大小有意義了
PBL 中包的大小無限增長是合理的,因為功能越添越多,而 PBF 中包太大(包裡 class 太多)表示這塊需要重構(劃分子包)。
3. Android 的命名規範
程式碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。
注意:即使純拼音命名方式也要避免採用。但國際通用的名稱,可視同英文,比如
toutiao
、douyin
等。
3.1 包名
Android 裡面有 package 的概念,所以需要約定一下包名命名規範。
包名全部小寫,不允許出現中文、大寫字母或者下劃線,前面為子模組命名,再根據 PBF 方式進行命名。
3.2 類名
類名都以 UpperCamelCase
風格編寫。
類名通常是名詞或名詞短語,介面名稱有時可能是形容詞或形容詞短語。現在還沒有特定的規則或行之有效的約定來命名註解型別。
名詞,採用大駝峰命名法,儘量避免縮寫,除非該縮寫是眾所周知的, 比如 HTML、URL,如果類名稱中包含單詞縮寫,則單詞縮寫的每個字母均應大寫。
類 | 描述 | 例如 |
---|---|---|
Activity 類 |
模組名 + Activity |
閃屏頁類 SplashActivity |
Fragment 類 |
模組名 + Fragment |
主頁類 HomeFragment |
Service 類 |
模組名 + Service |
時間服務 TimeService |
BroadcastReceiver 類 |
功能名 + Receiver |
推送接收 JPushReceiver |
ContentProvider 類 |
功能名 + Provider |
ShareProvider |
自定義 View | 功能名 + View/ViewGroup(元件名稱) | ShapeButton |
Dialog對話方塊 | 功能名+Dialog | ShapeButton |
Adapter 類 |
模組名 + Adapter |
課程詳情介面卡 LessonDetailAdapter |
解析類 | 功能名 + Parser |
首頁解析類 HomePosterParser |
工具方法類 | 功能名 + Utils 或 Manager |
執行緒池管理類:ThreadPoolManager 日誌工具類: LogUtils (Logger 也可)列印工具類: PrinterUtils |
資料庫類 | 功能名 + DBHelper |
新聞資料庫:NewsDBHelper |
自定義的共享基礎類 | Base + 基礎 |
BaseActivity , BaseFragment |
抽象類 | Base / Abstract 開頭 |
AbstractLogin |
異常類 | Exception 結尾 |
LoginException |
介面 | able / ible 結尾 / I 開頭 |
Runnable , Accessible ,ILoginView |
測試類的命名以它要測試的類的名稱開始,以 Test 結束。例如:HashTest
或 HashIntegrationTest
。
介面(interface):命名規則與類一樣採用大駝峰命名法,多以 able 或 ible 結尾,如 interface Runnable
、interface Accessible
。
注意:如果專案採用 MVP,所有 Model、View、Presenter 的介面都以 I 為字首,不加字尾,其他的介面採用上述命名規則。
3.3 方法名
方法名都以 lowerCamelCase
風格編寫。
方法名通常是動詞或動詞短語。
方法 | 說明 |
---|---|
initXX() |
初始化相關方法,使用 init 為字首標識,如初始化佈局 initView() |
isXX() , checkXX() |
方法返回值為 boolean 型的請使用 is/check 為字首標識 |
getXX() |
返回某個值的方法,使用 get 為字首標識 |
setXX() |
設定某個屬性值 |
handleXX() , processXX() |
對資料進行處理的方法 |
displayXX() , showXX() |
彈出提示框和提示資訊,使用 display/show 為字首標識 |
updateXX() |
更新資料 |
saveXX() , insertXX() |
儲存或插入資料 |
resetXX() |
重置資料 |
clearXX() |
清除資料 |
removeXX() , deleteXX() |
移除資料或者檢視等,如 removeView() |
drawXX() |
繪製資料或效果相關的,使用 draw 字首標識 |
3.4 變數命名
這裡的變數為廣義的變數,包括了常量、區域性變數、全域性變數等,它們的基礎規則是:
- 型別需要是名詞 / 名詞短語;
- 採用
lowerCamelCase
風格;
在具體的變數命名時,會根據該變數的型別不同而附加額外的命名規則:
型別 | 說明 | 例如 |
---|---|---|
常量 | 大寫 & 下劃線隔開,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 風格即可,私有變數也不要使用 m 開頭 |
private int tmp; |
Kotlin | 只讀變數使用 val ,可變變數使用 var ,儘可能使用 val |
var tmp = 0 val defaultIndex = 0 |
3.5 資源命名
Android 的資源包括:
資原始檔命名為全部小寫,採用下劃線命名法。
3.5.1 動畫資原始檔(anim/ 和 animator/)
安卓主要包含屬性動畫和檢視動畫,其檢視動畫包括補間動畫和逐幀動畫。屬性動畫檔案需要放在 res/animator/
目錄下,檢視動畫檔案需放在 res/anim/
目錄下。命名規則:{模組名_}邏輯名稱
。
說明:
{}
中的內容為可選,邏輯名稱
可由多個單詞加下劃線組成。例如:refresh_progress.xml
、market_cart_add.xml
、market_cart_remove.xml
。
如果是普通的補間動畫或者屬性動畫,可採用:動畫型別_方向
的命名方式。
例如:
名稱 | 說明 |
---|---|
fade_in |
淡入 |
fade_out |
淡出 |
push_down_in |
從下方推入 |
push_down_out |
從下方推出 |
push_left |
推向左方 |
slide_in_from_top |
從頭部滑動進入 |
zoom_enter |
變形進入 |
slide_in |
滑動進入 |
shrink_to_middle |
中間縮小 |
3.5.2 顏色資原始檔(color/)
color/ 是專門用於存放顏色相關資源的資料夾。命名規則:型別{_模組名}_邏輯名稱
。
說明:
{}
中的內容為可選。例如:sel_btn_font.xml
。
顏色資源也可以放於 res/drawable/
目錄,引用時則用 @drawable
來引用,但不推薦這麼做,最好還是把兩者分開。
3.5.3 圖片資原始檔(drawable/ 和 mipmap/)
res/drawable/
目錄下放的是點陣圖檔案(.png、.9.png、.jpg、.gif)或編譯為可繪製物件資源子型別的 XML 檔案,而 res/mipmap/
目錄下放的是不同密度的啟動圖示,所以 res/mipmap/
只用於存放啟動圖示,其餘圖片資原始檔都應該放到 res/drawable/
目錄下。
命名規則:型別{_模組名}_邏輯名稱
、型別{_模組名}_顏色
。
說明:
{}
中的內容為可選;型別
可以是可繪製物件資源型別,也可以是控制元件型別最後可加字尾_small
表示小圖,_big
表示大圖。
例如:
名稱 | 說明 |
---|---|
btn_main_about.png |
主頁關於按鍵 型別_模組名_邏輯名稱 |
btn_back.png |
返回按鍵 型別_邏輯名稱 |
divider_maket_white.png |
商城白色分割線 型別_模組名_顏色 |
ic_edit.png |
編輯圖示 型別_邏輯名稱 |
bg_main.png |
主頁背景 型別_邏輯名稱 |
btn_red.png |
紅色按鍵 型別_顏色 |
btn_red_big.png |
紅色大按鍵 型別_顏色 |
ic_avatar_small.png |
小頭像圖示 型別_邏輯名稱 |
bg_input.png |
輸入框背景 型別_邏輯名稱 |
divider_white.png |
白色分割線 型別_顏色 |
bg_main_head.png |
主頁頭部背景 型別_模組名_邏輯名稱 |
def_search_cell.png |
搜尋頁面預設單元圖片 型別_模組名_邏輯名稱 |
ic_more_help.png |
更多幫助圖示 型別_邏輯名稱 |
divider_list_line.png |
列表分割線 型別_邏輯名稱 |
sel_search_ok.xml |
搜尋介面確認選擇器 型別_模組名_邏輯名稱 |
shape_music_ring.xml |
音樂介面環形形狀 型別_模組名_邏輯名稱 |
如果有多種形態,如按鈕選擇器:sel_btn_xx.xml
,採用如下命名:
名稱 | 說明 |
---|---|
sel_btn_xx |
作用在 btn_xx 上的 selector |
btn_xx_normal |
預設狀態效果 |
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,前提是命名要規範。
3.5.4 佈局資原始檔(layout/)
命名規則:型別_模組名
、{模組名_}型別_邏輯名稱
。(也採用 PBF,方便檢視,尤其在大專案中)
說明:
{}
中的內容為可選。
例如:
型別 | 名稱 | 說明 |
---|---|---|
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 命名
命名規則:{模組名_}_邏輯名_view 縮寫(功能)
,例如: main_search_btn
、back_btn
。此外,採用 Kotlinx 直接獲取佈局檔案的時候,id 命名採用駝峰樣式。
說明:
{}
中的內容為可選。參考 GoogleSamples Demo:https://github.com/android/architecture-samples
例如:
型別 | 規範 | 命名示例 |
---|---|---|
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/)
選單相關的資原始檔應放在該目錄下。命名規則:{模組名_}邏輯名稱
說明:
{}
中的內容為可選。例如:main_drawer.xml
、navigation.xml
。
3.5.7 colors.xml
<color>
的 name
命名使用下劃線命名法,在你的 colors.xml
檔案中應該只是對映顏色的名稱一個 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>
使用這種格式,會非常容易重複定義 ARGB 值,而且如果應用要改變基色的話會非常困難。同時,這些定義是跟一些環境關聯起來的,如 button
或者 comment
,應該放到一個按鈕風格中,而不是在 colors.xml
檔案中。
相反,應該這樣做:
<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>
嚮應用設計者那裡要這個調色盤,名稱不需要跟 "green"
、"blue"
等等相同。"brand_primary"
、"brand_secondary"
、"brand_negative"
這樣的名字也是完全可以接受的。像這樣規範的顏色很容易修改或重構,會使應用一共使用了多少種不同的顏色變得非常清晰。通常一個具有審美價值的 UI 來說,減少使用顏色的種類是非常重要的。
注意:如果某些顏色和主題有關,那就單獨寫一個
colors_theme.xml
。
3.5.8 strings.xml
<string>
的 name
命名使用下劃線命名法,採用以下規則:{模組名_}邏輯名稱
,這樣方便同一個介面的所有 string
都放到一起,方便查詢。
名稱 | 說明 |
---|---|
main_menu_about |
主選單按鍵文字 |
friend_title |
好友模組標題欄 |
friend_dialog_del |
好友刪除提示 |
login_check_email |
登入驗證 |
dialog_title |
彈出框標題 |
button_ok |
確認鍵 |
loading |
載入文字 |
3.5.9 styles.xml
<style>
的 name
命名使用大駝峰命名法,幾乎每個專案都需要適當的使用 styles.xml
檔案,因為對於一個檢視來說,有一個重複的外觀是很常見的,將所有的外觀細節屬性(colors
、padding
、font
)放在 styles.xml
檔案中。 在應用中對於大多數文字內容,最起碼你應該有一個通用的 styles.xml
檔案,例如:
<style name="ContentText">
<item name="android:textSize">@dimen/font_normal</item>
<item name="android:textColor">@color/basic_black</item>
</style>
應用到 TextView
中:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/price"
style="@style/ContentText"/>
或許你需要為按鈕控制元件做同樣的事情,不要停止在那裡,將一組相關的和重複 android:xxxx
的屬性放到一個通用的 <style>
中。
4. Android 的註釋規範
4.1 類註釋
每個類完成後應該有作者姓名和聯絡方式的註釋,對自己的程式碼負責。
/**
* <pre>
* author : nanchen
* e-mail : xxx@xx
* time : 2021/01/18
* desc : xxxx 描述
* version: 1.0
* </pre>
*/
public class WelcomeActivity {
...
}
具體可以在 AS 中自己配製,進入 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 方法註釋
每一個成員方法(包括自定義成員方法、覆蓋方法、屬性方法)的方法頭都必須做方法頭註釋,在方法前一行輸入 /** + 回車
或者設定 Fix doc comment
(Settings -> Keymap -> Fix doc comment)快捷鍵,AS 便會幫你生成模板,我們只需要補全引數即可,如下所示。@param
, @return
, @throws
, @deprecated
這 4 種標記出現的時候,描述都不能為空。當描述無法在一行中容納,連續行至少需要再縮排 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 塊註釋
塊註釋與其周圍的程式碼在同一縮排級別。它們可以是 /* ... */
風格,也可以是 // ...
風格(//
後最好帶一個空格)。對於多行的 /* ... */
註釋,後續行必須從 *
開始, 並且與前一行的 *
對齊。以下示例註釋都是 OK 的。
/*
* This is okay.
*/
// And so
// is this.
/* Or you can
* even do this. */
註釋不要封閉在由星號或其它字元繪製的框架裡。
Tip:在寫多行註釋時,如果你希望在必要時能重新換行(即註釋像段落風格一樣),那麼使用
/* ... */
。
比如:
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
等這些註釋模板,回車後便會出現如下注釋。
// TODO: 17/3/14 需要實現,但目前還未實現的功能的說明
// FIXME: 17/3/14 需要修正,甚至程式碼是錯誤的,不能工作,需要修復的說明
4.5 註釋必須遵守的規範
4.5.1 不言自明的方法不要加註釋。
比如 Item getItem(int index)
是一段自說明的程式碼,我們可以直接從方法的命名就能知道它是幹嘛的,所以不需要增加註釋。
4.5.2 提測的程式碼不應該有 TODO 這樣的註釋
5. 程式碼樣式規範
5.1 使用標準大括號樣式
左大括號不單獨佔一行,與其前面的程式碼位於同一行:
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
我們需要在條件語句周圍新增大括號。例外情況:如果整個條件語句(條件和主體)適合放在同一行,那麼您可以(但不是必須)將其全部放在一行上。例如,我們接受以下樣式:
if (condition) {
body();
}
同樣也接受以下樣式:
if (condition) body();
但不接受以下樣式:
if (condition)
body(); // bad!
5.2 編寫簡短方法
在可行的情況下,儘量編寫短小精煉的方法。我們瞭解,有些情況下較長的方法是恰當的,因此對方法的程式碼長度沒有做出硬性限制。如果某個方法的程式碼超出 40 行,請考慮是否可以在不破壞程式結構的前提下對其拆解。
5.3 類成員的順序
這並沒有唯一的正確解決方案,但如果都使用一致的順序將會提高程式碼的可讀性,推薦使用如下排序:
- 常量(Kotlin 伴生物件放在開頭)
- 欄位
- 建構函式
- 重寫函式和回撥
- 公有函式
- 私有函式
- 內部類或介面
例如:
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
),那麼把重寫函式按照他們的生命週期進行排序是一個非常好的習慣,例如,Activity
實現了 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 函式引數的排序
在 Android 開發過程中,Context
在函式引數中是再常見不過的了,我們最好把 Context
作為其第一個引數。
正相反,我們把回撥介面應該作為其最後一個引數。
例如:
// 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 中的很多類都用到了鍵值對函式,比如 SharedPreferences
、Bundle
、Intent
,所以,即便是一個小應用,我們最終也不得不編寫大量的字串常量。
當時用到這些類的時候,我們 必須 將它們的鍵定義為 static final
欄位,並遵循以下指示作為字首。
類 | 欄位名字首 |
---|---|
SharedPreferences | PREF_ |
Bundle | BUNDLE_ |
Fragment Arguments | ARGUMENT_ |
Intent Extra | EXTRA_ |
Intent Action | ACTION_ |
說明:雖然 Fragment.getArguments()
得到的也是 Bundle
,但因為這是 Bundle
的常用用法,所以特意為此定義一個不同的字首。
例如:
// 注意:欄位的值與名稱相同以避免重複問題
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";
// 與意圖相關的項使用完整的包名作為值的字首
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
5.6 行長限制
程式碼中每一行文字的長度都應該不超過 160 個字元。雖然關於此規則存在很多爭論,但最終決定仍是以 160 個字元為上限,如果行長超過了 160(AS 視窗右側的豎線就是設定的行寬末尾 ),我們通常有兩種方法來縮減行長。
- 提取一個區域性變數或方法(最好)。
- 使用換行符將一行換成多行。
不過存在以下例外情況:
- 如果備註行包含長度超過 160 個字元的示例命令或文字網址,那麼為了便於剪下和貼上,該行可以超過 160 個字元。
- 匯入語句行可以超出此限制,因為使用者很少會看到它們(這也簡化了工具編寫流程)。
5.6.1 換行策略
這沒有一個準確的解決方案來決定如何換行,通常不同的解決方案都是有效的,但是有一些規則可以應用於常見的情況。
5.6.1.1 操作符的換行
除賦值操作符之外,我們把換行符放在操作符之前,例如:
int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne
+ theFinalOne;
賦值操作符的換行我們放在其後,例如:
int longName =
anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;
5.6.1.2 函式鏈的換行
當同一行中呼叫多個函式時(比如使用構建器時),對每個函式的呼叫應該在新的一行中,我們把換行符插入在 .
之前。
例如:
Picasso.with(context).load("https://blankj.com/images/avatar.jpg").into(ivAvatar);
我們應該使用如下規則:
Picasso.with(context)
.load("https://blankj.com/images/avatar.jpg")
.into(ivAvatar);
5.6.1.3 多引數的換行
當一個方法有很多引數或者引數很長的時候,我們應該在每個 ,
後面進行換行。
比如:
loadPicture(context, "https://blankj.com/images/avatar.jpg", ivAvatar, "Avatar of the user", clickListener);
我們應該使用如下規則:
loadPicture(context,
"https://blankj.com/images/avatar.jpg",
ivAvatar,
"Avatar of the user",
clickListener);
5.6.1.4 RxJava 鏈式的換行
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