Android編碼規(guī)范

一個(gè)項(xiàng)目從開(kāi)始開(kāi)發(fā)到后期的迭代版本,是多個(gè)人共同開(kāi)發(fā)的結(jié)果,所以當(dāng)團(tuán)隊(duì)人多起來(lái)的時(shí)候,編譯的規(guī)范就顯得很重要.這里整理了普遍使用的一些編譯規(guī)范,希望大家都遵守.

簡(jiǎn)單說(shuō)明

Android下的應(yīng)用程序大部分是基于java語(yǔ)言編寫的,所以規(guī)范都是按照java的來(lái)

Java 樣式規(guī)則


使用Javadoc 標(biāo)準(zhǔn)注釋

每個(gè)文件應(yīng)該在頂部,有版權(quán)的聲明接著包和導(dǎo)入語(yǔ)句 (由一個(gè)空行分隔每個(gè)塊),最后是類或接口聲明.在 Javadoc 注釋中,描述類或接口做些什么.

/*
 * Copyright (C) 2016 Globalegrow E-Commerce
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 做 X 和 Y  還有為 Z 提供一種抽象
 *
 * @author: zhengwu
 * @date: 2016-12-29
 */
public class Foo {
    ...
}

每個(gè)類和公共方法,你寫必須與至少一個(gè)句子描述的類或方法并包含的 Javadoc 注釋.這句話應(yīng)該開(kāi)始用第三人稱描述性動(dòng)詞.

例子:
單行注釋

/** 返回一個(gè)雙精度值的正確圓正平方根. */
static double sqrt(double a) {    ...}

or
多行注釋

/**
 * 構(gòu)造一個(gè)新的字符串,通過(guò)轉(zhuǎn)換指定的字節(jié)數(shù)組的
 * 使用平臺(tái)的默認(rèn)字符編碼. 
*/
public String(byte[] bytes) {    ...}

你不需要為簡(jiǎn)單的 get 和 set 方法寫 Javadoc ,如 setFoo() .如果該方法做更復(fù)雜的事物 (如強(qiáng)制約束或有一個(gè)重要的副作用),這個(gè)時(shí)候你必須記錄它.

寫簡(jiǎn)短的方法

在可行的情況下,保持方法小而且比較集中.我們認(rèn)識(shí)到,很長(zhǎng)的方法有時(shí)候是適當(dāng)?shù)? 所以沒(méi)有硬性限制放在方法長(zhǎng)度.如果一種方法超過(guò) 40 行左右,想想是否它可以被分解而不傷害程序的結(jié)構(gòu)。

在標(biāo)準(zhǔn)的地方定義字段

在頂部的文件或緊接使用它們的方法之前定義字段,這里建議在頂部的文件中定義,這樣方便查找.

限制變量范圍

將局部變量的范圍降到最低。通過(guò)這樣做,您增加可讀性和可維護(hù)性代碼并減少出錯(cuò)的可能性.每個(gè)變量應(yīng)該在包含變量所有使用的最內(nèi)層塊中聲明.

局部變量應(yīng)該在它們首次使用的點(diǎn)上聲明。 幾乎每個(gè)局部變量聲明都應(yīng)該包含一個(gè)初始化器。 如果你還沒(méi)有足夠的信息來(lái)明智地初始化變量,推遲聲明直到你這樣做.

異常是try-catch語(yǔ)句. 如果一個(gè)變量用一個(gè)拋出被檢查異常的方法的返回值初始化,它必須在try塊中初始化.如果值必須在try塊之外使用,那么它必須在try塊之前聲明,在那里它還不能明智地初始化:

// 初始化類cl, 這個(gè)類用來(lái)表示某種Set
Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}
...
// 使用這個(gè) set
s.addAll(Arrays.asList(args));

下面的這種寫法是推薦的

Set createSet(Class cl) {
    // 初始化類cl, 這個(gè)類用來(lái)表示某種Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// 使用這個(gè) set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

循環(huán)變量應(yīng)該在for語(yǔ)句本身中聲明,除非有強(qiáng)制的理由不這樣做:

for (int i = 0; i < n; i++) {    
    doSomething(i);
}

and

for (Iterator i = c.iterator(); i.hasNext(); ) {    
    doSomethingElse(i.next());
}
導(dǎo)入語(yǔ)句的順序

import語(yǔ)句的排序是:

  1. Android imports
  2. Imports from third parties (com, junit, net, org)
  3. java and javax

還有

  • 每個(gè)分組中按字母順序排列,大寫字母前加小寫字母(e.g. Z before a)
  • 在每個(gè)主要分組(android,com,junit,net,org,java,javax)之間用空行分隔
使用縮進(jìn)空格

使用4個(gè)空格縮進(jìn)塊,而不是制表符
我們使用8個(gè)空格縮進(jìn)進(jìn)行換行,包括函數(shù)調(diào)用和賦值,例如,這是正確的:

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

下面這個(gè)是不正確的

Instrument i =    
    someLongExpression(that, wouldNotFit, on, one, line);
換行

沒(méi)有一個(gè)精確的公式解釋如何換行,并且經(jīng)常不同的解決方案是有效的.然而,有一些規(guī)則可以應(yīng)用于常見(jiàn)的情況, 這里列舉了常見(jiàn)的幾種.

int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne 
        + theFinalOne;
int longName =
        anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;
Picasso.with(context)
        .load("http://ribot.co.uk/images/sexyjoe.jpg")
        .into(imageView);
loadPicture(context,
        "http://ribot.co.uk/images/sexyjoe.jpg",
        mImageViewProfilePicture,
        clickListener,
        "Title of the picture");
命名約定

變量的命名

  • 非公共,非靜態(tài)字段名以m開(kāi)頭
  • 靜態(tài)字段名稱以s開(kāi)頭
  • 其他字段以小寫字母開(kāi)頭
  • 公共靜態(tài)最終字段(常量)所以大寫字母并以下畫線連接

例子

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;
}

Android 的許多元素(如SharedPreferences,Bundle或Intent)都使用鍵值對(duì)方法,因此對(duì)這個(gè)也規(guī)范如下:
所有的變量前面都加static final

| 組件 | 命名前綴 |
| ------------- |: -----:|
|SharedPreferences |PREF_
|Bundle |BUNDLE_
|Fragment Arguments |ARGUMENT_
|Intent Extra | EXTRA_
|Intent Action |ACTION_
|BroadCast Action|ACTION_

請(qǐng)注意,F(xiàn)ragment - Fragment.getArguments()的參數(shù)也是一個(gè)Bundle。 然而,因?yàn)檫@是一個(gè)很常見(jiàn)的使用Bundles,我們?yōu)樗鼈兌x一個(gè)不同的前綴。
例子:

// 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";

如果是啟動(dòng)Activity

public static Intent getStartIntent(Context context, User user) {
    Intent intent = new Intent(context, ThisActivity.class);
    intent.putParcelableExtra(EXTRA_USER, user);
    return intent;
}

如果是啟動(dò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:如果我們提供上面描述的方法,extras和參數(shù)的鍵應(yīng)該是私有的,因?yàn)樗鼈儾恍枰┞对陬愅獠俊?/p>

類的命名

類名使用大寫駱駝拼寫法來(lái)命名,如果類是繼承了相應(yīng)的組件,則要以組件名字結(jié)尾來(lái)命名,如:SignInActivity, SignInFragment, ImageUploaderService,ChangePasswordDialog

| 類 | 命名格式 | 示例 |
| ------------- |: -------------:|: -----:|
| Activity | 描述+Activity |HomeActivity,MainActivity |
|Fragment |描述+Fragment | 如購(gòu)物車,CartFragment|
| Service | 描述+Service | PushMessageService |
| BroadcastReceiver | 描述+Receiver | OnlineReceiver |
|ContentProvider | 描述+Receiver| 如聯(lián)系人的內(nèi)容提供者,ContactsProvider|
|Dialog|描述+Dialog|如普通的選擇提示對(duì)話框,ChoiceDialog|
|Adapter|描述+Adapter|如聯(lián)系人列表,ContactsListAdapter|
|基礎(chǔ)功能類|Base+父類名| 如BaseActivity,BaseFragment|
|工具類|描述+Utils|如處理字符串的工具類,StringUtils|
|管理類|描述+Manager|如管理聯(lián)系人的類,ContactsManager|

方法的命名

| 命名風(fēng)格 | 含義 |
| ------------- |: -----:|
|initXX()|初始化,如初始化所有控件initView()|
|isXX()|是否滿足某種要求,如是否為注冊(cè)用戶isRegister()|
|displayXX()|顯示提示信息,如displayXXDialog,displayToast,displayXXPopupWindow|
|saveXX()| 保存XX數(shù)據(jù)|
|resetXX()| 重置XX數(shù)據(jù)|

資源的命名

資源的名字是用小寫的、下劃線連接

圖片資源的命名,沒(méi)有在下面列出來(lái)的圖片可以參考: 圖片的用途_用到的地方 來(lái)命名,如bg_sign_in, start_splash

drawables.png

用到的一些圖標(biāo)的命名

icon.png
select.png

Layout 下資源的命名

| 組件 | 類名字 | 布局文件名 |
| ------------- |: -------------:|: -----:|
|Activity| UserProfileActivity| activity_user_profile.xml|
|Fragment| SignUpFragment | fragment_sign_up.xml|
|Dialog| ChangePasswordDialog| dialog_change_password.xml|
|AdapterView Item| -- | item_person.xml|
|抽取出來(lái)復(fù)用的xml布局(include)| --|include_bottom_tabs|

當(dāng)XML元素沒(méi)有任何內(nèi)容時(shí),您必須使用自動(dòng)關(guān)閉標(biāo)記。

正確的

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

不對(duì)的

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

Menu 下資源的命名

與布局文件類似,菜單文件應(yīng)與組件的名稱匹配。 例如,如果我們定義將要在UserActivity中使用的菜單文件,則文件的名稱應(yīng)為activity_user.xml.

注意這里不要加menu,因?yàn)橐呀?jīng)在menu目錄下了

Values 下的文件命名

values文件夾中的資源文件應(yīng)為復(fù)數(shù),如:strings.xml,styles.xml,colors.xml,dimens.xml,attrs.xml

colors.xml: 定義顏色值, 如果是通用的顏色,用具體的顏色名稱來(lái)表示.如果是只有單獨(dú)的界面用到的或者有 代表性的,則用如goods_price,progressbar_bg,main_window_background
themes.xml: 定義主題,所有的主題名字以Theme結(jié)尾
styles.xml: 定義使用的樣式,所有的樣式名字以Style結(jié)尾
strings.xml: 定義所有使用的字符串, 字符串名稱以標(biāo)識(shí)其所屬性的前綴開(kāi)頭,看下面表格:

| 前綴 | 描述 |
| ------------- |: -----:|
|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"|

id 的命名

都是用小寫字母、下劃線鏈接

| 組件 | 描述 |
| ------------- |: -----:|
|TextView|_text|
|ImageView|_image|
|Button|_button|
|CheckBox|_check|
|ProgressBar|_bar或者_(dá)view|
|ScrollView|_view|
|自定義view|_view|
|LinearLayout|_layout或者_(dá)container|
|RelativeLayout|_layout或者_(dá)container|
|Fragment|fragment|
|Menu|menu
|

<ImageView
    android:id="@+id/profile_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<menu>
    <item
        android:id="@+id/menu_done"
        android:title="Done" />
</menu>
使用標(biāo)準(zhǔn)括號(hào)樣式

大括號(hào)不自己另起一行; 他們和他們之前的代碼在同一行:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

我們需要在條件語(yǔ)句周圍添加括號(hào). 特例:如果整個(gè)條件(條件和正文)符合一行,您可以(但不是必須)將它全部放在一行上,例如,這是可以接受的:

if (condition) {
    body();
}

下面這樣也可以

if (condition) body();

但是這樣就不可以
if (condition)
body(); // 不好的!容易造成歧義

限制代碼每一行的長(zhǎng)度

代碼中的每行文字長(zhǎng)度應(yīng)試最多為100個(gè)字符,也有特例:

  • 如果注釋行包含示例命令或長(zhǎng)度超過(guò)100個(gè)字符的文字URL,那么該行可能長(zhǎng)于100個(gè)字符,以便于剪切和粘貼.
  • import行可以超過(guò)限制,因?yàn)槿藗兒苌倏吹剿鼈儯ㄟ@也簡(jiǎn)化了工具寫入)
正確使用首字母縮略詞

將縮寫詞作為命名變量,方法和類中的單詞,以使名稱更易讀:

canvas.png
使用TODO注釋

對(duì)臨時(shí)代碼使用TODO注釋,短期解決方案,或者足夠好但不完美的代碼。 TODO應(yīng)在所有大寫字母中包含字符串TODO,后跟冒號(hào):

Java 語(yǔ)言規(guī)則


不要忽略異常的處理

可能很容易編寫完全忽略異常的代碼,例如:

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

不要這樣做.雖然你可能認(rèn)為你的代碼永遠(yuǎn)不會(huì)遇到這個(gè)錯(cuò)誤條件或者它不重要的處理它,忽略異常如上所示在你的代碼中為別人觸發(fā)一天.你必須以原則的方式處理你的代碼中的每一個(gè)異常; 具體處理根據(jù)情況而變化.

因該使用下面的下發(fā)來(lái)替換(按優(yōu)先順序):

  • 將異常拋出給方法的調(diào)用者
void setServerPort(String value) throws NumberFormatException {
    serverPort = Integer.parseInt(value);
}
  • 拋出一個(gè)適合你的抽象層次的新異常
void setServerPort(String value) throws ConfigurationException {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        throw new ConfigurationException("Port " + value + " is not valid.");
    }
}
  • 處理錯(cuò)誤并在catch {}塊中替換一個(gè)適當(dāng)?shù)闹?/li>
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        serverPort = 80;  // default port for server
    }
}
不捕獲泛型異常
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!
}
導(dǎo)入具體的包路徑

當(dāng)你想使用包foo中的類Bar時(shí),有兩種可能的方法來(lái)導(dǎo)入它:

  • import foo.*;
  • import foo.Bar; //使用這個(gè)方式,代碼可讀性更強(qiáng).

其他還需要注意的地方


  • 縮放保證不失真的,圖片可以做成點(diǎn)9圖
  • strings.xml中使用%1$s實(shí)現(xiàn)字符串的通配
  • 代碼中不出現(xiàn)中文,最多注釋中可以出現(xiàn)中文

Android 官方規(guī)范
android-guidelines
簡(jiǎn)書

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

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

  • Android 編碼規(guī)范 1. 前言 這份文檔是 Google Java Code Style 的譯文,并稍有添加...
    人失憶閱讀 493評(píng)論 0 3
  • 作者:李旺成 時(shí)間:2016年4月3日 1. 前言 這份文檔參考了 Google Java 編程風(fēng)格規(guī)范和 Goo...
    diygreen閱讀 40,228評(píng)論 19 224
  • androidstudio集成checkstyle提交前校驗(yàn)方法,將pre-commit文件copy到工程目錄.g...
    Chris鍋閱讀 1,072評(píng)論 0 0
  • Android編碼規(guī)范 源文件基礎(chǔ) 文件名 源文件以其最頂層的類名來(lái)命名,大小寫敏感,文件擴(kuò)展名為.java。 文...
    呼呼哥閱讀 1,114評(píng)論 0 0
  • 介紹 為什么需要編碼規(guī)范? 編碼規(guī)范對(duì)于程序員而言尤為重要,有以下幾個(gè)原因: ? 一個(gè)軟件的生命周期中,80%...
    lucas777閱讀 506評(píng)論 0 0

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