Backlight87
9/3/2017 - 4:21 PM

项目规范-命名规范

项目规范-命名规范

Android项目规范
1 编码规范
代码的命名总体上要求不能使用拼音,并且尽量不要使用缩写,以避免误解。
1.1 项目名称
基于Android Studio 的项目的名称必须为英文,不含任何字符,且单词首字母必须大写,结尾追加Project后缀。
例如『我的通讯录』的项目名称为:MyAddressBookProject
1.2 模块名称
基于Android Studio,每个项目都会被划分成若干个模块(Module),要求模块名称单词首字母必须大写。
例如『通用库模块』的名称为:CommonLib
1.3 项目概览
如果你按照规范对整个项目进行命名的话,你会看到如下格式的项目:
MyAddressBookProject
        ├── MyAddressBook
        ├── CommonLib
        ├── ModuleA
        ├── ModuleB
        .
        .
        .
1.4 包名
包的命名有以下两种方式,各项目内部必须统一:
  1. 项目包名以模块进行划分,包括模块内的子模块,当模块无法在继续划分成子模块的时候,以类型进行划分。
  对于功能通用性很高的组件,我们都归类为common模块,对于仅限于某个模块内通用的组件,则应该归类在所属模块内,不应该放在common模块。详细划分情况参照以下示例:
com.meitu.project(项目根目录)
      ├── common(通用模块)
      │   ├── network
      │   ├── util
      │   ├── database
      │   └── widget
      ├── home(主页模块)
      │   ├── activity
      │   ├── fragment
      │   ├── service
      │   └── widget
      └── setting(设置模块)
          ├── activity
          ├── feedback(设置模块的子模块,反馈模块)
          │   ├── activity
          │   ├── fragment
          │   ├── service
          │   └── widget
          ├── fragment
          ├── service
          └── widget
  2. 项目的根目录分通用模块和应用模块两种。通用模块指的是整个项目通用的功能模块,不同功能模块位于各自的包内。应用模块以app命名,
  内部以功能模块分包,每个功能模块可以有更多子功能模块包,当模块无法在继续划分成子模块的时候,以类型进行划分。
com.meitu.project(项目根目录)
      ├── network(网络模块)
      ├── util(工具模块)
      ├── database(数据库模块)
      ├── widget(通用控件模块)
      └── app(所有功能模块)
          ├── home(主页模块)
          │   ├── activity
          │   ├── fragment
          │   ├── service
          │   └── widget
          └── setting(设置模块)
              ├── activity
              ├── feedback(设置模块的子模块,反馈模块)
              │   ├── activity
              │   ├── fragment
              │   ├── service
              │   └── widget
              ├── fragment
              ├── service
              └── widget
1.5 类名
类名应该是一个名词,必须为英文,且每个单词的首字母必须大写。
  ● 例如『视频剪辑类』的名称为:VideoEdictor
1.6 接口
对于接口名称的定义,我们需要分三种情况:
  ● 定义回调方法接口,要求以描述 + Callback的方式命名。
例如相机的回调接口取名为:CameraCallback
  ● 定义监听器的接口,要求以 描述 + Listener 的方式命名。
例如监听下载进度的监听器取名为:DownloadListener
  ● 定义抽象层次的接口,要求以 I + 描述 的方式命名(这点需要讨论,因为Google的源码并没有这样写,
  要根据大家的习惯定夺)。
例如抽象的下载接口取名为:IDownloader
1.7 抽象类命名
抽象类名称以Abs + 描述的方式定义。
  ● 例如『抽象的下载类』的名称为:AbsDownloader
1.8 静态常量和枚举命名
静态常量和枚举类型的名称应该由全部大写英文单词组成,多个单词之间通过下划线连接,以类型_描述的方式命名。
  ● 例如『上传和下载数据的URL』的静态常量应该被定义为:
public static final String URL_UPLOAD_DATA = "http://xxx";
public static final String URL_DOWNLOAD_DATA = "http://xxx";
  ● 例如『HTTP请求方式』的枚举类型应该被定义为:
public enum HttpMethod {
    POST,
    GET
}
1.9 成员变量命名
普通变量应该由英文单词组成,且首字母必须是小写 m(member),之后的每个单词首字母必须大写。
  ● 例如『用户名』成员变量应该被定义为:
public String mUserName = "xxx";
1.10 局部变量命名
普通变量应该由英文单词组成,且首字母必须是小写,之后的每个单词首字母必须大写。
  ● 例如『用户名』局部变量应该被定义为:
String userName = "xxx";
1.11 方法命名
方法名应该是动宾结构(动词+名词),且首字母必须是小写动词,之后的每个单词首字母必须大写,
参数的命名规范与普通变量的命名一样。
  ● 例如『获取用户名』方法应该被定义为:
public String getUserName() { ... }
  ● 例如『设置用户名』方法应该定义为:
public void setUserName(String userName) { ... }
1.12 Activity命名
Activity要求以 功能描述 + Activity 的方式命名,例如:
  ● 设置页的Activity,取名为:SettingActivity
  ● 剪裁图片的Activity,取名为:CropPictureActivity
1.13 Fragment命名
Fragment要求以 功能描述 + Fragment 的方式命名,例如:
  ● 设置页的Fragment,取名为:SettingFragment
  ● 剪裁图片的Fragment,取名为:CropPictureFragment
1.14 Service命名
Service要求以 功能描述 + Service 的方式命名,例如:
  ● 在后台播放音乐的Service,取名为:MusicService
1.15 BroadcastReceiver命名
BroadcastReceiver要求以 功能描述 + Receiver 的方式命名,例如:
  ● 监听网络状态变化的BroadcastReceiver,取名为:NetworkStateReceiver
1.16 View命名
View要求以 功能描述 + View 的方式命名,例如:
  ● 绘制mask图层的View,取名为:DrawMaskView
1.17 ViewGroup命名
ViewGroup要求以 功能描述 + Layout 的方式命名,例如:
  ● Android自带的线性布局,取名为:LinearLayout
1.18 实体类命名
实体类要求以 功能描述 + [Bean | Entity | Info] 的方式命名,例如:
  ● 图片信息实体类,取名为:PictureInfo
  ● 音乐信息实体类,取名为:MusicBean
1.19 控件成员变量命名
控件成员变量的命名方式有两种,但是项目内部必须统一:
  1. m + 控件缩写 + 描述
  2. m + 描述 + 控件缩写
单词之间以驼峰命名法衔接,首字母小写,控件的缩写要求以每个单词的首字母组成,例如:
  ● 用户名输入框(EditText),取名为:mEtUserName或mUserNameEt
  ● 文件下载进度(ProgressBar),取名为:mPbFileDownloadProgress或mFileDownloadProgressPb
控件全称控件缩写TextViewtvImageViewivButtonbtnImageButtonibtnRadioGrouprgRadioButtonrbtnCheckBoxcbProgressBarpbSeekBarsbEditTextetListViewlvExpandableListViewelvRecyclerViewrvCradViewcvWebViewwvLinearLayoutllFrameLayoutflRelativeLayoutrlScrollViewsvHorizontalScrollViewhsvViewPagervpGridViewgv
1.20 代码注释
1.20.1 常用注释标签
@author
通过该标签注明代码的编写者和编写日期,例如:@author Jerry 2016.01.28
@param
通过该标签注明方法参数的描述,例如:@param userName 用户名称
@return
通过该标签注明方法返回值的描述,例如:@return 返回用户名称或者null
@see
通过该标签注明其他相关类或方法,例如:@see #getUserName()
{@link}
通过该标签引用某个类或方法,例如:{@link #getUserName()}
@deprecated
通过该标签注明某个方法或类已经弃用,并说明情况,例如:@deprecated 该方法已经废除,请使用{@link #setUserName(String)
1.20.2 成员变量注释
理论上你的成员变量名应该能够见名知意,如果不行就写上注释。
1.20.3 类注释
类名要求在注释里写明类的用途和作者。
例如美颜相机首页的背景图会在用户切换页面的时候轻微移动,所以写了个自定义控件叫HomeBackgroundView,我们写了以下注释:
/**
 * 美颜相机主页带平移动画的背景图,当用户滑动屏幕切换页面的时候,背景图片会在水平方向上轻微移动,这时候
 * 我们只移动ImageView的前景图(src),背景图片不动。该控件用法很简单,只需要在{@link ViewPager}
 * 的{@link OnPageChangeListener#onPageScrolled(int, float, int)}方法里调用{@link #onPageScrolled(int)}
 * 方法即可,当页面发生偏移的时候就会触发图片的轻微移动。另外,你还可以通过{@link #setTranslateRatio(float)}
 * 方法设置图片移动距离占页面偏移距离的比例,默认值是10%。
 *
 * @author hjd 2015.01.26
 * @see #onPageScrolled(int)
 * @see #setTranslateRatio(float)
 */
public class HomeBackgroundView extends ImageView {

}
1.20.4 方法注释
原则上来说每一个方法都要求有注释,不论长短简繁,并且具有参数或返回值的方法,必须对参数和返回值进行注释说明,这有助于提高代码的可读性。
例如我们有一个设置年龄的方法叫setAge(int age),从方法名称上我们就可以知道它的作用,但是其内部还做了一些其他处理,
这些处理是方法命无法体现的,所以加上一段注释说明就很有必要了:
/**
 * 设置用户的年龄,当 age < 0 的时候会设置 age = 0,当 age > 100 的时候会设置 age = 100。另外你可以
 * 通过{@link #getAge()}方法获取用于的年龄。
 *
 * @param age 用户年龄[0, 100]
 * @see #getAge()
 */
public void setAge(int age) {
    if (age < 0) {
        age = 0;
    } else if (age > 100) {
        age = 100;
    }
    this.age = age;
}
1.21 将字面值定义成常量
尽量避免直接使用字面值,因为单纯的数字或字符串容易让人误解,同时也不利于后期的维护(例如统一修改某个值)。
  ● 例如我们有个值是0.8,它是『默认缩放比例』。
错误的写法
float ratio = 0.8F;
正确的写法
private static final float DEFAULT_RATIO = 0.8F;
float ratio = DEFAULT_RATIO;
1.22 动态文案必须使用String.format
项目中需要动态设置显示的文案时,要求通过String.format(...)方法进行文案的填充,而不是使用字符串拼接的方式。这样做有利于项目的多语言。
  ● 例如我们有个文案是“My name is xxx”。
错误的写法
String introTxt = "My name is " + name;
textView.setText(introTxt);
正确的写法
<string name="setting_introduction">My name is %1$s</string>
String introFormat = getResources().getString(R.string.setting_introduction);
String introTxt = String.format(introFormat, name);
textView.setText(introTxt);
2 资源规范
资源的命名除了style之外,统一以小写字母加下划线的形式,并且以资源所属模块名称开头,接资源描述,最后以类型或状态名称结尾。由于资源没有像代码一样有包可以作为模块划分,所以我们才会要求增加前缀,这样做的好处是分类明显,便于功能的移植,同时也让项目更整洁。
2.1 控件ID
控件ID有以下两种命名方式,但是项目内部必须统一:
  1. 模块名_描述_控件缩写
  2. 控件缩写_模块名_描述
控件名称的缩写,我们要求由控件全称每个单词的首字母组成,对于名称只有一个单词的控件会给出例外缩写名称。
控件全称控件缩写TextViewtvImageViewivButtonbtnImageButtonibtnRadioGrouprgRadioButtonrbtnCheckBoxcbProgressBarpbSeekBarsbEditTextetListViewlvExpandableListViewelvRecyclerViewrvCradViewcvWebViewwvLinearLayoutllFrameLayoutflRelativeLayoutrlScrollViewsvHorizontalScrollViewhsvViewPagervpGridViewgv
2.2 anim
动画资源的定义要求以模块名_描述的方式命名。
  ● 例如某个模块有个不断放大缩小的按钮,该动画资源属于欢迎页模块,我们根据功能描述定义如下的动画资源文件:
res/anim/模块名_xxx.xml
2.3 color
颜色资源我们分为两种,一种是单纯的颜色值定义,另一种是代表某个状态的颜色资源定义,例如按钮的文字颜色根据点击状态的不同会有不同的颜色。
2.3.1 无状态颜色定义
无状态颜色资源的定义要求以模块名_描述的方式命名。
  ● 例如某个模块顶部标题栏的背景色,该颜色资源属于设置页模块,我们根据情况定义如下的颜色资源:
<color name="模块名_top_title_bar_bg">#EEB5E5</color>
2.3.2 有状态颜色定义
有状态颜色资源定义要求以模块名_描述_状态的方式命名。
  ● 例如某个模块顶部标题栏返回按钮的文字颜色,该颜色资源有两种状态,分别是点击和未点击,我们将定义如下的两种颜色:
<color name="模块名_top_title_bar_bg_normal">#EEB5E5</color>
<color name="模块名_top_title_bar_bg_pressed">#EEB5E5</color>
--------------------------------------------------------------------------------
结尾的状态名称需要根据该资源被引用时所触发的状态决定:
  ● 当所有状态都为false的时候,使用normal作为结尾。
<item android:state_pressed="false" android:state_focused="false" android:color="@color/模块名   _xxx_color_normal" />
  ● 当有一个以上的状态为 true 的时候,使用被激活状态的名称作为结尾,多个状态名称之间以下划线分割。
<item android:state_enabled="true" android:state_pressed="true" android:color="@color/模块名_xxx_color_enabled_pressed" />
--------------------------------------------------------------------------------
以下是常用的几个激活状态对应的后缀名称:
状态后缀android:state_pressed="true"pressedandroid:state_checked="true"checkedandroid:state_selected="true"selectedandroid:state_focused= "true"focusedandroid:state_enabled= "true"enabledandroid:state_enabled= "false"disabled
2.3.3 通用颜色定义和引用
项目中可能会有一些通用颜色的定义,其他地方的颜色直接引用这些常用颜色,通用颜色以color_颜色值_百分比透明度的方式命名。
  ● 例如设计师定下项目的主色调值是#AA33B5E5,我们计算出透明度为66%,然后我们会以下面的方式定义颜色:
<color name="color_33b5e5_66">#AA33B5E5</color>
<color name="setting_top_title_bar_bg_color">@color/color_33b5e5_66</color>
2.4 drawable
图像资源要求以类型名称结尾。另外我们根据图像是否代表某个状态分为两种类型,一种是无状态图像,另一种是代表某个状态的有状态图像,例如按钮的背景图根据点击状态的不同会有不同的背景。
2.4.1 无状态图像名称
无状态图像名称的定义要求以图像类型结尾。
  ● 例如某个模块返回键图标,我们将图标名称定义成:
模块名_xxx_back_ic.png
  ● 例如某个模块的按钮背景图是通过 <shape> 定义的,我们将背景图名称定义成:
res/drawable/模块名_xxx_btn_bg.xml
可用的图像类型如下所示:
类型名称对应属性bgandroid:backgroundicandroid:drawableLefticandroid:drawableRighticandroid:drawableTopicandroid:drawableBottomicandroid:src
2.4.2 有状态图像名称
有状态图像名称的定义除了要求以图像类型结尾,还要加上图像所代表的状态名称。
  ● 例如某个模块的返回键按钮点的背景图有两种状态,分别是点击和未点击,我们将背景图名称定义成:
模块名_xxx_bg_normal.png
模块名_xxx_bg_pressed.png
--------------------------------------------------------------------------------
结尾的状态名称需要根据该资源被引用时所触发的状态决定:
  ● 当所有状态都为false的时候,使用normal作为结尾。
<item android:state_pressed="false" android:state_focused="false" android:drawable="@color/模块名_xxx_bg_normal" />
  ● 当有一个以上的状态为true的时候,使用被激活状态的名称作为结尾,多个状态名称之间以下划线分割。
<item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/模块名_xxx_bg_enabled_pressed" />
--------------------------------------------------------------------------------
以下是常用的几个激活状态对应的后缀名称:
状态后缀android:state_pressed="true"pressedandroid:state_checked="true"checkedandroid:state_selected="true"selectedandroid:state_focused= "true"focusedandroid:state_enabled= "true"enabledandroid:state_enabled= "false"disabled
2.4.3 selector
通过<selector>标签定义的多态资源实际上也属于drawable资源,唯一的不同是它能够根据控件状态的不同而变化。我们在定义这类多态资源文件的时候,跟定义drawable一样也要在结尾加上图像的类型名称,并且追加sel后缀用于标识该drawable资源是通过<selector>定义的。<selector>内部<item>标签所引用的资源名称定义参照前面color和drawable的有状态资源定义方式。
  ● 例如某个模块的按钮背景图,它具有点击和为点击两种状态,我们将文件名定义成:
res/drawable/模块名_xxx_btn_bg_sel.xml
内部<item>的定义如下所示:
<item android:state_pressed="false" android:drawable="@drawable/模块名_xxx_btn_bg_normal" />
<item android:state_pressed="true" android:drawable="@drawable/模块名_xxx_btn_bg_pressed" />
2.4.4 shape
通过<shape>标签定义的图形资源,也是drawable资源,我们遵守drawable资源的命名规则即可,无需添加后缀。如果你需要在<selector>中使用的<shape>定义的简单图形,那直接定义在<selector>的<item>中,而不是另外写一个<shape>文件。
  ● 例如某个模块简单图形,我们将文件名定义成:
res/drawable/模块名_描述_bg.xml
2.4.5 layer-list
通过<layer-list>标签定义的图形资源,也是drawable资源,我们除了遵守drawable资源的命名规则之外,还要在结尾追加list后缀用于标识该drawable资源是通过<layer-list>标签定义的。
  ● 例如某个模块的按钮点击状态的背景图,我们将文件名定义成:
res/drawable/模块名_描述_bg_list_pressed.xml
2.4.6 通用 drawable 定义和引用
在项目中可能会存在一些通用的图像资源,我们将这些通用图像资源归类为common模块,其他模块如果需要使用通用资源,则通过<drawable>标签定义属于自己模块的图像资源,并引用对应的通用资源。
  ● 例如项目有个通用的返回图标,设置页顶部标题栏需要使用该图标,那么我们会有如下定义:
res/drawable-xhdpi/common_back_ic.png
<drawable name="setting_top_title_bar_back_ic">@drawable/common_back_ic</drawable>
2.4.7 多后缀排序
当Drawable资源具有多个后缀时,我们按照以下规则进行排序:
  ● 模块名_描述_[bg | ic ...]_[sel | list ...]_[pressed | focused | checked ...]
2.5 layout
2.5.1 布局命名方式
布局文件名称的定义要求以布局所属的模块名称开头,后面紧跟着是布局对应的Activity或Fragment的名称,如果布局不是直接用于Activity或Fragment,那么就以模块名称加描述内容命名。
  ● 例如主页模块的Activity类名为HomeActivity,那么对应的布局应该定义成:
res/layout/home_activity.xml(由于home已经代表了模块名称,所以不必再多写一个home)
  ● 例如设置模块的意见反馈Fragment类名为FeedbackFragment,那么对应的布局应该定义成:
res/layout/setting_feeback_fragment.xml(setting必填,因为用于定位模块)
2.5.2 RelativeLayout规范
在使用<RelativeLayout>时建议不要出现以@+id/xxx的方式填写相对布局的ID。
  ● 不规范用法
该用法在没有定义Button(btn_test2)之前就对其进行引用。
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_test1"
        android:text="Button1"
        android:layout_toRightOf="@+id/btn_test2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/btn_test2"
        android:text="Button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>
  ● 正确用法
先定义基础位置的按钮Button(btn_test2),然后在写相对位置的按钮Button(btn_test1)。
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_test2"
        android:text="Button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/btn_test1"
        android:text="Button1"
        android:layout_toRightOf="@id/btn_test2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>
2.6 string
2.6.1 字符串命名方式
字符串的定义要求以模块名_描述的方式命名。
  ● 例如主页有个按钮的文案为“个人信息”,那么对应的定义如下:
<string name="home_personal_info">个人信息</string>
2.6.2 不需要翻译的字符串
如果项目中有字符串不需要多语言翻译时,我们要求将这些字符串定义在values/donottranslate.xml文件中。
2.7 dimen
尺寸的定义要求以所属模块名称开头,后面紧跟尺寸的描述。
  ● 例如主页个人信息按钮的宽度,对应的定义如下:
<dimen name="home_personal_info_btn_width">50dp</dimen>
2.8 style
样式的定义要求名称的每个单词首字母必须大写,并且需要事先对每一个模块定义一个开头样式,每个模块下的子样式都必须继承该模块开头样式用于标识该子样式属于该模块。
  ● 以主页模块为例,我们会事先定义主页的模块style:
<style name="Home" />
假设我们有个顶部标题栏的样式,那么我们会有如下定义:
<style name="Home.TopTitleBarStyle">...</style>
不同模块之间的继承必须通过 parent 属性定义,例如我们想继承通用模块的顶部标题栏样式,那么我们应该有如下定义:
<style name="Home.TopTitleBarStyle" parent="Common.TopTitleBarStyle">...</style>