文件的命名
類的命名
命名應(yīng)該遵循駝峰命名法
對于繼承自 Android 組件的類來說砸讳,命名應(yīng)以該組件的名稱結(jié)尾墩划;例如: SignInActivity
, SignInFragment
, ImageUploaderService
, ChangePasswordDialog
。
Res 中文件的命名
資源文件應(yīng)該以小寫 + 下劃線( _ )的格式命名疫萤。
圖片文件
以下是對于圖片文件的命名習(xí)慣
Asset Type | Prefix | Example |
---|---|---|
Action bar | ab_ |
ab_stacked.9.png |
Button | btn_ |
btn_send_pressed.9.png |
Dialog | dialog_ |
dialog_top.9.png |
Divider | divider_ |
divider_horizontal.9.png |
Icon | ic_ |
ic_star.png |
Menu | menu_ |
menu_submenu_bg.9.png |
Notification | notifi_ |
notifi_bg.9.png |
Tabs | tab_ |
tab_pressed.9.png |
對于圖標(biāo)的命名習(xí)慣
Asset Type | Prefix | Example |
---|---|---|
Icons | ic_ |
ic_star.png |
Launcher icons | ic_launcher |
ic_launcher_calendar.png |
Menu icons and Action Bar icons | ic_menu |
ic_menu_archive.png |
Status bar icons | ic_stat_notify |
ic_stat_notify_msg.png |
Tab icons | ic_tab |
ic_tab_recent.png |
Dialog icons | ic_dialog |
ic_dialog_info.png |
對于選擇器狀態(tài)的命名習(xí)慣
State | Suffix | Example |
---|---|---|
Normal | _normal |
btn_order_normal.9.png |
Pressed | _pressed |
btn_order_pressed.9.png |
Focused | _focused |
btn_order_focused.9.png |
Disabled | _disabled |
btn_order_disabled.9.png |
Selected | _selected |
btn_order_selected.9.png |
布局文件
布局文件應(yīng)該和將要用于的 Android 組件的名稱相匹配签舞,但是這次應(yīng)以組件的名稱開頭。例如灌灾, 如果我們?yōu)?SignInActivity
,創(chuàng)建布局文件,那布局文件的名稱就應(yīng)該為 activity_sign_in.xml
.
Component | Class Name | Layout Name |
---|---|---|
Activity | UserProfileActivity |
activity_user_profile.xml |
Fragment | SignUpFragment |
fragment_sign_up.xml |
Dialog | ChangePasswordDialog |
dialog_change_password.xml |
AdapterView item | --- | item_person.xml |
Partial layout | --- | partial_stats_bar.xml |
一個(gè)特殊的情況就是在為 Adapter 中的子項(xiàng)創(chuàng)建布局的時(shí)候悲柱, 例如锋喜, 顯示 ListView 中的內(nèi)容。在這種情況下豌鸡,布局文件的前綴應(yīng)該為 item_
應(yīng)該注意到還有一個(gè)特殊情況的存在嘿般,那就是在創(chuàng)建一個(gè)布局中的其中一小塊布局時(shí),在這種情況下就應(yīng)該使用前綴 partial_
menu 文件
與布局文件的命名的規(guī)則相似直颅,menu 文件也應(yīng)該和將要用于的 Android 組件的名稱相匹配博个。例如,當(dāng)我們在為 UserActivity
創(chuàng)建 menu 文件時(shí)功偿,那 menu 文件的名稱就應(yīng)該是 activity_user.xml
命名規(guī)則是不把單詞 menu
作為名稱的一部分,因?yàn)檫@些文件已經(jīng)存放在 menu
的文件下了往堡。
資源文件
在 values
文件夾中的資源文件在命名時(shí)應(yīng)該為復(fù)數(shù)械荷。例如, strings.xml
, styles.xml
, colors.xml
, dimens.xml
, attrs.xml
代碼規(guī)范
Java 語言的規(guī)范
不要忽略異常的處理
永遠(yuǎn)不要編寫出以下的代碼
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) { }
}
不要認(rèn)為你的代碼永遠(yuǎn)不會觸發(fā)此類的異陈腔遥或者不足以處理,或者如以上代碼似的,在你的代碼里留下缺口讓別人在以后幫你來填上.你必須按照規(guī)范來捕獲每一個(gè)異常.也可以查看 Android 官方的文檔描述.
不要捕獲通用的異常
永遠(yuǎn)不要編寫以下的代碼
try {
someComplicatedIOFunction(); // may throw IOException
someComplicatedParsingFunction(); // may throw ParsingException
someComplicatedSecurityFunction(); // may throw SecurityException
// phew, made it all the way
} catch (Exception e) { // I'll just catch all exceptions
handleError(); // with one generic handler!
}
具體原因可以查看 Android 官方文檔描述
不要使用 finalizers
不要使用 finalizers (不知道 finalize 的可以查看這里). 即便 finalizer 最終都是會被調(diào)用的但是什么時(shí)候會別調(diào)用是沒有保證的. 在大多數(shù)的情況下,你可以通過好的異常捕獲機(jī)制來取代 finalizer. 如果在某種情況下你必須要使用到它, 定義一個(gè) close()
方法(或者類似的)然后準(zhǔn)確的說明一下什么時(shí)候該方法會被調(diào)用到.
規(guī)范的引用
這是一個(gè)不好的引用編寫: import foo.*;
這是一個(gè)合格的引用編寫: import foo.Bar;
更多信息查看這里
Java 風(fēng)格規(guī)范
變量的定義與命名
變量應(yīng)該定義在文件頭部的位置,并且應(yīng)該遵循以下的命名規(guī)則.
- Private, 非靜態(tài)變量應(yīng)該以 m 開頭命名
- Private, 靜態(tài)變量應(yīng)該以 s 開頭命名
- 其余的變量應(yīng)該以小寫字母開頭
- 靜態(tài)的常量應(yīng)該都是以大寫字母加下劃線的格式命名. 例如,
ALL_CAPS_WITH_UNDERSCORES
.
例子如下
public class MyClass {
public static final int SOME_CONSTANT = 42;
public int publicField;
private static MyClass sSingleton;
int mPackagePrivate;
private int mPrivate;
protected int mProtected;
}
將英文的縮略詞也看做成一個(gè)單詞
Good | Bad |
---|---|
XmlHttpRequest |
XMLHTTPRequest |
getCustomerId |
getCustomerID |
String url |
String URL |
long id |
long ID |
Inside Code Naming 代碼內(nèi)部命名
Important : 請不要使用拼音以及數(shù)字6窒埂!穆咐!
====== 常用縮寫 ======
完整單詞 縮寫
A
average ——> avg
B
back ——> bk
background ——> bg
break ——> brk
buffer ——> buf
C
color ——> cr(clr)
control ——> ctrl
D
data ——> dat
delete ——> del
document ——> doc
E
edit ——> edt
error ——> err
escape ——> esc
F
flag ——> flg
form ——> frm
G
grid ——> grd
I
increment ——> inc
information ——> info
initial ——> init
insert ——> ins
image ——> img
L
label ——> lab
length ——> len
list ——> lst
library ——> lib
M
manager ——> mngr(mgr)
message ——> msg
O
Oracle ——> Ora
P
panorama ——> pano
password ——> pwd
picture ——> pic
point ——> pt
position ——> pos
print ——> prn
program ——> prg
S
server ——> srv
source ——> src
statistic ——> stat
string ——> str
Sybase ——> Syb
T
temp ——> tmp
text ——> txt
U
user ——> usr
W
window ——> wnd(win)
使用空格來進(jìn)行縮進(jìn)
使用4 個(gè)空格來進(jìn)行代碼塊的縮進(jìn)
if (x == 1) {
x++;
}
使用** 8 個(gè)空格**來進(jìn)行代碼的換行
Instrument i =
someLongExpression(that, wouldNotFit, on, one, line);
大括號的使用規(guī)范
左大括號應(yīng)該跟在其之前的代碼在同一行上
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
如果條件語句跟結(jié)果語句正好可以在同一行上并且其長度也小于同一行的最大長度限制, 則可以省略大括號
例如
if (condition) body();
錯(cuò)誤的范例
if (condition)
body(); // bad!
注解
注解的應(yīng)用
根據(jù) Android 官方文檔, 在 Java 中對于一些預(yù)先確定的注解的標(biāo)準(zhǔn)應(yīng)用如下
-
@Override
: 該注解必須用與任何時(shí)候想要重寫或者實(shí)現(xiàn)父類的某個(gè)方法的時(shí)候. 例如,當(dāng)你使用了@inheritDocs
標(biāo)簽,并且是源于一個(gè)類而并不是接口的時(shí)候,你必須同時(shí)也在此方法上加上@Override
標(biāo)簽. -
@SuppressWarnings
: 該標(biāo)簽只有在遇到無法忽略的警告的條件下才可以使用. 如果一個(gè)警告符合"無法忽略掉"的條件時(shí),該標(biāo)簽是必須需要被使用的,為的是保證所有的警告都能反映出代碼中實(shí)際存在的問題.
更多關(guān)于注解的規(guī)范請參考這里
注解格式
- 類,方法和構(gòu)造函數(shù): 當(dāng)注解被用于類,方法和構(gòu)造函數(shù)的時(shí)候,應(yīng)該將注解位于注釋的下面,并且每個(gè)注解作為一行的形式.如下所示
/* This is the documentation block about the class */
@AnnotationA
@AnnotationB
public class MyAnnotatedClass { }
- 對象: 注解應(yīng)該與對象保持在同一行,除非該行達(dá)到了最大字符的限制數(shù).
@Nullable @Mock DataManager mDataManager;
限制變量的作用域
局部變量的作用域應(yīng)該保持到最小.這樣可以增加代碼的可讀性和維護(hù)性,并且降低出錯(cuò)的概率.
局部變量應(yīng)該盡量在它第一次被調(diào)用的時(shí)候被聲明出來.而且聲明局部變量時(shí)應(yīng)該初始化該變量,如果你還沒有足夠的信息來初始化該變量,那就應(yīng)該推遲聲明直到擁有足夠的信息來初始化此變量的時(shí)候.更多信息可查看這里
日志的規(guī)范
請使用公司通用的 LogUtil
類來取代 Android 原生的 Log
類來打印日志.
類成員排列的規(guī)范
這部分沒有強(qiáng)制的要求,但是使用一種合乎邏輯并且常用的方式來排列類成員,可以增強(qiáng)代碼的可讀性
- 常量
- 對象
- 構(gòu)造函數(shù)
- 重寫和回調(diào)函數(shù)(包括公有的和私有的)
- 公有函數(shù)
- 私有函數(shù)
- 內(nèi)部類及內(nèi)部接口
例如:
public class Child extends Parent {
private static final int CONSTANT = 1;
private String mName;
private int mAge;
public Child(String name, int age) {
mName = name;
mAge = age;
}
@Override
public void changeName() {
...
}
public void setName(String name) {
mName = name;
}
private void setSomething() {
...
}
static class AnInnerClass {
}
}
如果你的類是繼承自Android 的組件,例如 Activity 和 Fragment, 比較好的習(xí)慣是按照該組件的生命周期來重寫方法.例如,如果你有一個(gè) Activity 實(shí)現(xiàn)了 onCreate()
, onDestroy()
, onPause()
和 onResume()
,則正確的順序?yàn)?
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() {}
}
函數(shù)中參數(shù)的順序
在編寫 Android 的代碼時(shí),函數(shù)中含有參數(shù) Context
是非常常見的.如果遇到這種情況,那么必須將Context作為第一個(gè)參數(shù).
對應(yīng)的回調(diào)接口應(yīng)該永遠(yuǎn)作為函數(shù)的最后一個(gè)參數(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);
字符串常量的命名
Android SDK 中包含很多需要鍵值對的元素例如, SharedPreferences
, Bundle
和 Intent
.即使在寫一個(gè)很小的 app 應(yīng)用時(shí),也會產(chǎn)生很多字符串常量.
當(dāng)使用以上組件的時(shí)候,你必須將字符串定義為 static final
,并且它們的前綴應(yīng)該遵循以下的命名規(guī)則:
Element | Field Name Prefix |
---|---|
SharedPreferences | PREF_ |
Bundle | BUNDLE_ |
Fragment Arguments | ARGUMENT_ |
Intent Extra | EXTRA_ |
Intent Action | ACTION_ |
Handler Action | ACTION_ |
雖然 Fragment.getArguments()
返回的也是一個(gè) Bundle,但是為了用于區(qū)分,所以使用 ARGUMENT_
作為其前綴.
// Note the value of the field is the same as the name to avoid duplication issues
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";
// Intent-related items use full package name as value
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
Fragment 和 Activity 中的參數(shù)
當(dāng)數(shù)據(jù)通過 Intent
或 Bundle
傳遞給 Fragment
和 Activity
的時(shí)候, Key 的命名必須要遵循以上的命名規(guī)范.
當(dāng) Activity
或 Fragment
需要接受參數(shù)的時(shí)候, 需要創(chuàng)建一個(gè) public static
的方法來創(chuàng)建與之相關(guān)的 Intent
或 Fragment
.
Activity 的情況下,通常將方法命名為 getStartIntent()
:
public static Intent getStartIntent(Context context, User user) {
Intent intent = new Intent(context, ThisActivity.class);
intent.putParcelableExtra(EXTRA_USER, user);
return intent;
}
Fragment 的情況下,通常將方法命名為 newInstance()
,通過傳入的參數(shù)來創(chuàng)建 Fragment
public static UserFragment newInstance(User user) {
UserFragment fragment = new UserFragment;
Bundle args = new Bundle();
args.putParcelable(ARGUMENT_USER, user);
fragment.setArguments(args)
return fragment;
}
注意 1:此類方法應(yīng)該聲明在類的前部, onCreate()
方法之前
注意 2:如果我們已經(jīng)聲明了以上的方法,那么為 Intent 或 Bundle 聲明的 Key
應(yīng)該是 private
, 因?yàn)椴恍枰愔鈦硎褂?
行長度的限制
一行代碼的長度不應(yīng)該超過100 個(gè)字符,如果一行代碼過長,通常有如下兩種方法來減少代碼的長度:
- 提取出一個(gè)
局部變量
或方法
(推薦) - 通過換行將一行代碼變?yōu)槎嘈?/li>
有兩種例外的情況可以允許行代碼超過 100 個(gè)字符
- 無法換行的代碼,例如: 網(wǎng)址 URL
-
package
和import
的聲明
換行的規(guī)范
這里也沒有強(qiáng)制行的規(guī)范,但是有幾條比較通用的規(guī)范希望可以遵守
運(yùn)算符
當(dāng)要在運(yùn)算符處進(jìn)行換行的時(shí)候,換行應(yīng)該在運(yùn)算符之前,例如:
int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne
+ theFinalOne;
但是以上規(guī)則不適用于 =
運(yùn)算符,換行應(yīng)該在等號運(yùn)算符之后,例如:
int longName =
anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;
方法鏈的情況下
當(dāng)多個(gè)方法在同一行組合在一起成為方法鏈的時(shí)候.例如, Builder 模式下,每一個(gè)方法應(yīng)該獨(dú)立成一行,并換行應(yīng)該在 .
之前.
Picasso.with(context).load("http://ribot.co.uk/images/sexyjoe.jpg").into(imageView);
Picasso.with(context)
.load("http://ribot.co.uk/images/sexyjoe.jpg")
.into(imageView);
多個(gè)參數(shù)的情況下
當(dāng)一個(gè)函數(shù)多個(gè)參數(shù)并且參數(shù)過長時(shí),我們應(yīng)該在 ,
后進(jìn)行換行.
loadPicture(context, "http://ribot.co.uk/images/sexyjoe.jpg", mImageViewProfilePicture, clickListener, "Title of the picture");
loadPicture(
context,
"http://ribot.co.uk/images/sexyjoe.jpg",
mImageViewProfilePicture,
clickListener,
"Title of the picture"
);
針對于 RxJava 的規(guī)范
Rx 的方法鏈同樣需要換行.每一個(gè)操作必須獨(dú)立為一行,而且換行應(yīng)該在 .
之前.
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;
}
});
}
XML 的規(guī)范
使用自結(jié)束標(biāo)簽
當(dāng)一個(gè) XML 里的元素內(nèi)沒有其他元素時(shí),應(yīng)該使用自結(jié)束標(biāo)簽
這是正確的:
<TextView
android:id="@+id/text_view_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
這是錯(cuò)誤的:
<!-- Don't do this! -->
<TextView
android:id="@+id/text_view_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TextView>
資源的命名
資源的 ID 和名稱都應(yīng)該是小寫 + 下劃線的格式
ID 的命名
ID 應(yīng)該以控件的名稱作為前綴來命名.例如:
Element | Prefix |
---|---|
TextView |
text_ |
ImageView |
image_ |
Button |
button_ |
Menu |
menu_ |
ImageView 例子:
<ImageView
android:id="@+id/image_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Menu 例子:
<menu>
<item
android:id="@+id/menu_done"
android:title="Done" />
</menu>
字符串
字符串的名字應(yīng)該以一個(gè)可以標(biāo)明其所屬領(lǐng)域的前綴來做開頭. 例如, registration_email_hint
或 registration_name_hint
.如果一個(gè)字符串不屬于任何的領(lǐng)域,那應(yīng)該遵循以下規(guī)則:
Prefix | Description |
---|---|
error_ |
An error message |
msg_ |
A regular information message |
title_ |
A title, i.e. a dialog title |
action_ |
An action such as "Save" or "Create" |
Style 和 Theme
不同于其他的資源命名規(guī)范, Style 中的名字應(yīng)該遵循駝峰命名法
Color
color 中顏色的命名應(yīng)該遵循小寫 + 下劃線的格式
提高 Android 性能的編碼規(guī)范
不要在 Android 程序里使用 enum
雖然使用 enum 很方便,但是會比使用靜態(tài)變量產(chǎn)生多于兩倍的內(nèi)存消耗,所以 Android 官方強(qiáng)烈建議不要在Android程序里面使用到 enum.
使用 Android Typedef Annotations 可以代替 enum, 具體的使用方法請參考這里
關(guān)于數(shù)組遍歷
static class Foo {
int mSplat;
}
Foo[] mArray = ...
// 最慢,消耗最多
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
// 推薦
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
-
zero()
是最慢的方法,因?yàn)?JIT 還不能對當(dāng)數(shù)組進(jìn)行遍歷時(shí)每次都要去獲得數(shù)組的長度進(jìn)行優(yōu)化. -
one()
更快一點(diǎn), 因?yàn)樗械臄?shù)據(jù)都拿出來存放在局部變量里,避免了查找.只有提供了數(shù)組的長度對性能有了一定的提升 -
two()
在沒有 JIT 的設(shè)備里是最快的,但在有 JIT 的設(shè)備里與one()難分上下.它使用了 Java 1.5 版本中的增強(qiáng)版語法
所以應(yīng)該默認(rèn)使用增強(qiáng)版的 for 循環(huán).