Android 項目及編碼的規(guī)范

文件的命名

類的命名

命名應(yīng)該遵循駝峰命名法
對于繼承自 Android 組件的類來說,命名應(yīng)以該組件的名稱結(jié)尾;例如: SignInActivity, SignInFragment, ImageUploaderService, ChangePasswordDialog

Res 中文件的命名

資源文件應(yīng)該以小寫 + 下劃線( _ )的格式命名。

圖片文件

以下是對于圖片文件的命名習慣

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

對于圖標的命名習慣

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)的命名習慣

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

一個特殊的情況就是在為 Adapter 中的子項創(chuàng)建布局的時候, 例如, 顯示 ListView 中的內(nèi)容。在這種情況下,布局文件的前綴應(yīng)該為 item_
應(yīng)該注意到還有一個特殊情況的存在,那就是在創(chuàng)建一個布局中的其中一小塊布局時,在這種情況下就應(yīng)該使用前綴 partial_

menu 文件

與布局文件的命名的規(guī)則相似,menu 文件也應(yīng)該和將要用于的 Android 組件的名稱相匹配。例如,當我們在為 UserActivity 創(chuàng)建 menu 文件時,那 menu 文件的名稱就應(yīng)該是 activity_user.xml
命名規(guī)則是不把單詞 menu 作為名稱的一部分,因為這些文件已經(jīng)存放在 menu 的文件下了。

資源文件

values 文件夾中的資源文件在命名時應(yīng)該為復(fù)數(shù)。例如, strings.xml, styles.xml, colors.xml, dimens.xml, attrs.xml

代碼規(guī)范

Java 語言的規(guī)范

不要忽略異常的處理

永遠不要編寫出以下的代碼

void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) { }
}

不要認為你的代碼永遠不會觸發(fā)此類的異?;蛘卟蛔阋蕴幚?或者如以上代碼似的,在你的代碼里留下缺口讓別人在以后幫你來填上.你必須按照規(guī)范來捕獲每一個異常.也可以查看 Android 官方的文檔描述.

不要捕獲通用的異常

永遠不要編寫以下的代碼

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)用的但是什么時候會別調(diào)用是沒有保證的. 在大多數(shù)的情況下,你可以通過好的異常捕獲機制來取代 finalizer. 如果在某種情況下你必須要使用到它, 定義一個 close() 方法(或者類似的)然后準確的說明一下什么時候該方法會被調(diào)用到.

規(guī)范的引用

這是一個不好的引用編寫: import foo.*;
這是一個合格的引用編寫: import foo.Bar;
更多信息查看這里

Java 風格規(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;
}

將英文的縮略詞也看做成一個單詞

Good Bad
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
String url String URL
long id long ID

Inside Code Naming 代碼內(nèi)部命名

Important : 請不要使用拼音以及數(shù)字!??!

====== 常用縮寫 ======

完整單詞 縮寫

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)

使用空格來進行縮進

使用4 個空格來進行代碼塊的縮進

if (x == 1) {
    x++;
}

使用** 8 個空格**來進行代碼的換行

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();

錯誤的范例

if (condition)
    body();  // bad!

注解

注解的應(yīng)用

根據(jù) Android 官方文檔, 在 Java 中對于一些預(yù)先確定的注解的標準應(yīng)用如下

  • @Override: 該注解必須用與任何時候想要重寫或者實現(xiàn)父類的某個方法的時候. 例如,當你使用了 @inheritDocs 標簽,并且是源于一個類而并不是接口的時候,你必須同時也在此方法上加上 @Override 標簽.
  • @SuppressWarnings: 該標簽只有在遇到無法忽略的警告的條件下才可以使用. 如果一個警告符合"無法忽略掉"的條件時,該標簽是必須需要被使用的,為的是保證所有的警告都能反映出代碼中實際存在的問題.
    更多關(guān)于注解的規(guī)范請參考這里
注解格式
  • 類,方法和構(gòu)造函數(shù): 當注解被用于類,方法和構(gòu)造函數(shù)的時候,應(yīng)該將注解位于注釋的下面,并且每個注解作為一行的形式.如下所示
/* This is the documentation block about the class */
@AnnotationA
@AnnotationB
public class MyAnnotatedClass { }
  • 對象: 注解應(yīng)該與對象保持在同一行,除非該行達到了最大字符的限制數(shù).
@Nullable @Mock DataManager mDataManager;

限制變量的作用域

局部變量的作用域應(yīng)該保持到最小.這樣可以增加代碼的可讀性和維護性,并且降低出錯的概率.
局部變量應(yīng)該盡量在它第一次被調(diào)用的時候被聲明出來.而且聲明局部變量時應(yīng)該初始化該變量,如果你還沒有足夠的信息來初始化該變量,那就應(yīng)該推遲聲明直到擁有足夠的信息來初始化此變量的時候.更多信息可查看這里

日志的規(guī)范

請使用公司通用的 LogUtil 類來取代 Android 原生的 Log 類來打印日志.

類成員排列的規(guī)范

這部分沒有強制的要求,但是使用一種合乎邏輯并且常用的方式來排列類成員,可以增強代碼的可讀性

  • 常量
  • 對象
  • 構(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, 比較好的習慣是按照該組件的生命周期來重寫方法.例如,如果你有一個 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() {}

}

函數(shù)中參數(shù)的順序

在編寫 Android 的代碼時,函數(shù)中含有參數(shù) Context 是非常常見的.如果遇到這種情況,那么必須將Context作為第一個參數(shù).
對應(yīng)的回調(diào)接口應(yīng)該永遠作為函數(shù)的最后一個參數(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, BundleIntent.即使在寫一個很小的 app 應(yīng)用時,也會產(chǎn)生很多字符串常量.
當使用以上組件的時候,你必須將字符串定義為 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() 返回的也是一個 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ù)

當數(shù)據(jù)通過 IntentBundle 傳遞給 FragmentActivity的時候, Key 的命名必須要遵循以上的命名規(guī)范.
ActivityFragment 需要接受參數(shù)的時候, 需要創(chuàng)建一個 public static 的方法來創(chuàng)建與之相關(guān)的 IntentFragment.
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īng)該超過100 個字符,如果一行代碼過長,通常有如下兩種方法來減少代碼的長度:

  • 提取出一個局部變量方法(推薦)
  • 通過換行將一行代碼變?yōu)槎嘈?/li>

有兩種例外的情況可以允許行代碼超過 100 個字符

  • 無法換行的代碼,例如: 網(wǎng)址 URL
  • packageimport 的聲明
換行的規(guī)范

這里也沒有強制行的規(guī)范,但是有幾條比較通用的規(guī)范希望可以遵守
運算符
當要在運算符處進行換行的時候,換行應(yīng)該在運算符之前,例如:

int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne
        + theFinalOne;

但是以上規(guī)則不適用于 = 運算符,換行應(yīng)該在等號運算符之后,例如:

int longName =
        anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;

方法鏈的情況下
當多個方法在同一行組合在一起成為方法鏈的時候.例如, Builder 模式下,每一個方法應(yīng)該獨立成一行,并換行應(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);

多個參數(shù)的情況下
當一個函數(shù)多個參數(shù)并且參數(shù)過長時,我們應(yīng)該在 , 后進行換行.

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 的方法鏈同樣需要換行.每一個操作必須獨立為一行,而且換行應(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é)束標簽

當一個 XML 里的元素內(nèi)沒有其他元素時,應(yīng)該使用自結(jié)束標簽
這是正確的:

<TextView
    android:id="@+id/text_view_profile"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

這是錯誤的:

<!-- 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)該以一個可以標明其所屬領(lǐng)域的前綴來做開頭. 例如, registration_email_hintregistration_name_hint.如果一個字符串不屬于任何的領(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 官方強烈建議不要在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() 是最慢的方法,因為 JIT 還不能對當數(shù)組進行遍歷時每次都要去獲得數(shù)組的長度進行優(yōu)化.
  • one() 更快一點, 因為它所有的數(shù)據(jù)都拿出來存放在局部變量里,避免了查找.只有提供了數(shù)組的長度對性能有了一定的提升
  • two() 在沒有 JIT 的設(shè)備里是最快的,但在有 JIT 的設(shè)備里與one()難分上下.它使用了 Java 1.5 版本中的增強版語法
    所以應(yīng)該默認使用增強版的 for 循環(huán).

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,062評論 25 709
  • Android編碼規(guī)范 源文件基礎(chǔ) 文件名 源文件以其最頂層的類名來命名,大小寫敏感,文件擴展名為.java。 文...
    呼呼哥閱讀 1,119評論 0 0
  • 作者:李旺成 時間:2016年4月3日 1. 前言 這份文檔參考了 Google Java 編程風格規(guī)范和 Goo...
    diygreen閱讀 40,236評論 19 224
  • Android 編碼規(guī)范 1. 前言 這份文檔是 Google Java Code Style 的譯文,并稍有添加...
    人失憶閱讀 497評論 0 3
  • 你說人事無常 終于明白你說的傷 你說要帶我去飛向遠方 卻被疾病折去鋒芒 忍著痛,看見你蒼白的笑容 淚水,在那刻止不...
    青青子衿0917閱讀 282評論 0 2

友情鏈接更多精彩內(nèi)容