Android开发日记(十八)—— Android 项目规范

通常我们为了项目的维护会定下一系列的规范开发来提高自己或者团队之间的写代码的效率,正所谓无规矩不成方圆。

Hello Android.jpg

Android Studio的使用

Android 开发首选 Android Studio,一个好的IDE能让你事半功倍。编码规范使用 Android Studio 默认的模板规范即可,这也是比较方便的方法。同时也要注意以下几点,可以让你的团队协作更加协调:

  1. 统一调整 IDE 的编码方式为 UTF-8
  2. 编辑完代码后不要忘记格式化(即 Ctrl+Alt+L 快捷键)
  3. 尽量保证团队之间的 IDE 版本与 Gradle 版本一致,最好的做法是及时更新保证与官方最新版一致。
  4. 代码提交前进行代码检查(Analyze->Inspect Code),可以消除代码中的警告,减少不必要的错误。
  5. 擅用 //TODO 注释来标记未做完或需要其他人接手的工作
  6. 善用AS插件来提高开发效率,像 GsonFormat——将json字符串转换成一个Java实体类的工具,CodeGlance——在右边可以预览代码,实现快速定位等工具都是非常棒的。

命名规范

最有效的命名方式是使用英文拼写和语法,可以让阅读者易于理解,尽量避免使用中文拼音的情况(常见地名和通用名称例外,比如HangZhou,alibaba等)。禁止使用中英文混合或者完全中文的方式。

包名

通常一个app需要一个顶级包名,而这个包名通常跟公司的域名相关。一级包名是顶级域名,通常为com,edu,gov,net,org等,二级包名为公司名,三级包名根据应用进行命名。

比如我的个人域名为 cpacm.net,那么我个人所做的app包名一般为net.cpacm.yourappname。

再来说如何分包?
分包的方式说法不一,有的人喜欢按照层次来分,比如说将所有 Activity 放在同一个包下。有的人喜欢按照功能来分,将一个功能的 ActivityModelAdapter等一些文件放入同一个包内。具体的例子可以参考谷歌的 iosched 样例。

我个人比较推荐的方式是按照功能进行分包,但同时会将数据层再单独分离出来,详细的例子可以看看我之前写的文章——说说我自己常用的 Android 架构。不过每个人的习惯并不一致,所以在这点上可以随意发挥,只要不导致整个项目结构混乱就成。

类名

一个类会包含(按顺序地):

  1. 许可证或版权信息(如有需要)
  2. package语句
  3. import语句
  4. 一个顶级类
    四个部分用一个空行隔开。

类名都以 UpperCamelCase 风格编写。

在 Android 中与系统相关的类通常以组件名为后缀标识。

  • Activity 类,命名为 Activity 为后缀,如 LoginActivity
  • Fragment 类,命名以 Fragment 为后缀,如 LoginFragment
  • Service 类,命名以 Service 为后缀,如 DownloadService
  • BroadcastReceiver类,命名以Receiver为后缀,如 JPushReceiver
  • ContentProvider类, 命名以Provider为后缀,如ShareProvider
  • Adapter 类,命名以 Adapter 为后缀,如 ListAdapter

其他一些常见的命名:

  • 工具管理类,命名以 Utils 或者 Manager 为后缀,如 EncryptUtilsUserManager
  • 实体类,命名以 Bean 或者 Info 为后缀,如 UserBean
  • 接口实现类,命名以 Impl 或者 Listener 为后缀,如 ApiImpl
  • 数据库类,命名以 Dao 或者 DbHelper 为后缀,如 UserDao
  • 自定义控件类,命名以 View 或者 Layout 为后缀,如 SimpleSliderLayout

方法名

方法名都以 lowerCamelCase 风格编写。

方法名通常是动词或动词短语。下划线可能出现在JUnit测试方法名称中用以分隔名称的逻辑组件。并不存在唯一正确的方式来命名测试方法。

常见的方法名称:

方法 说明
getXX()/setXX() 获取/设置属性值,如 getUserName()
isXX()/checkXX()/hasXX() 用于返回 Boolean 值的方法,如 isGirl(),hasPermission()
initXX() 初始化相关方法,如 initView()
loadXX()/handleXX() 读取数据或者对数据处理时的方法,如 loadData()
disPlayXX()/showXX() 显示相关信息,如 showToast()

一般方法的命名都是以动词为前缀,后面加上动作的对象。

常量名

常量名命名模式为 CONSTANT_CASE,全部字母大写,用下划线分隔单词。

1
2
3
4
5
// Constant
static final int NUMBER = 5;

// Not constant
static String nonFinal = "non-final";

这些名字通常是名词或名词短语。

每个常量都是一个静态final字段,但不是所有静态final字段都是常量。在决定一个字段是否是一个常量时, 考虑它是否真的感觉像是一个常量。

变量名

在Google其它编程语言风格中使用的特殊前缀或后缀,如name_, mName, s_name和kName,在Java编程风格中都不再使用。

现在在 Android 非常量字段名的命名有两种方式,一种是在特定的字段名上加上特殊前缀或后缀,如普通成员变量命名以 mCamelCase 样式命名,静态变量以 sCamelCase 命名。另一种则是完全使用 lowerCamelCase 命名,如 camelCase 变量名。

虽然两种命名方式都可,但切记不要在同一个项目中同时使用,这样只会让代码看得糟糕。当然个人推荐变量名以 lowerCamelCase 风格编写。

参数名,局部变量名以 lowerCamelCase 风格编写

临时变量通常被取名为i、j、k、m和n,它们一般用于整型;c、d、e,它们一般用于字符型。

类型变量可用以下两种风格之一进行命名:

  1. 单个的大写字母,后面可以跟一个数字(如:E, T, X, T2)。
  2. 以类命名方式,后面加个大写的T(如:RequestT, FooBarT)。

关于Android中相关控件的命名,控件变量命名可以在后缀加上控件名称或者控件名称的缩写,如login+Button=loginButton/loginBtn。平常习惯控件名缩写的话推荐使用控件名称的缩写来作为后缀。

Android 资源文件

Android资源文件基本上都采取使用下划线_来连接词语。

布局文件 layout

必须全部单词小写,单词间以下划线分割,使用名词或名词词组

界面相关布局

命名方式为 界面_模块.xml
通常 Activity 或者 Fragment 等类名要与其布局文件相对应,如:

LoginActivity.java -> activity_login.xml
BookFragment.java -> fragment_book.xml
DateDialog.java -> dialog_date.xml
SettingPopupWindow.java -> ppw_setting.xml

列表项布局

命名方式为 控件_模块_item.xml

一般关于列表项的命名则以 item 作为前缀,如:item_user.xml 表示这个布局文件用在用户列表中。

但我更喜欢下面这种方式的命名:
listview_user_item -> 表示这是用于 listview 的用户列表项。
recyclerview_user_item -> 表示这是用于 recyclerview 的用户列表项。
gridview_user_item -> 表示这是用于 gridview 的用户列表项。

而此时你自定义了一个 GroupView 需要列表项去填充,比如说一个 RefreshLayout:
refresh_user_item -> 表示这是用于 RefreshLayout 的用户列表项。

包含项

命名方式为 模块_描述.xml
在界面布局中,如 activity_user_header 表示为用户界面的头部布局。
在列表布局中,如 listview_user_header 表示为用户列表的头部布局。

图片资源 drawable

全部小写,采用下划线命名法,加前缀区分

用途 命名规则 名称
图标 ic\_模块名[\_用途] ic_home 或 ic_media_info
普通文件 模块\_用途[\_状态描述] search_background 或者 layerlist_progress_horizontal 或者 btn_xx_focused

动画资源 anim

也是要全部小写,使用下划线来分隔词组。
命名规则为 模块_用途[_状态描述],如:

fade_out->淡出
push_down_in->从下方推入

菜单资源 menu

命名规则为: menu_模块[_用途]
如:menu_shelf -> 表示为书架上的菜单选项
其中菜单内部的id命名规则为 action_用途,如:action_manage

好吧,其实资源的命名没有那么多死板的规则,只要能看到自己命名的名字能立马明白它的作用就行了。当然不止自己也必须让团队的其他人能明白。

Values下的命名方式

色调(color)

禁止在layout直接使用 “#000000” 赋予颜色,
在你的colors.xml文件中应该只是映射颜色的名称一个ARGB值,而没有其它的。不要为特定的UI定义特定的颜色值,这样只会导致颜色值重复定义。

Don’t

1
2
3
<color name="chapter_select_area_bg">#fff5f5f5</color>
<color name="content_text_color">#ff404040</color>
<color name="et_hit_text_color">#ffacacac</color>

Do

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>

<!-- 常用字体颜色 -->
<color name="black">#000000</color>
<color name="black_alpha">#8A000000</color>
<color name="black_alpha_more">#64000000</color>
<color name="black_normal">#DE000000</color>
<color name="white">#FFFFFF</color>
<color name="white_alpha">#8AFFFFFF</color>
<color name="white_normal">#DEFFFFFF</color>
<color name="white_normal_more">#33FFFFFF</color>
<color name="white_less">#FFFAFA</color>


<color name="transparent">#00000000</color>
</resources>

一个美观的 app 是不会充斥太多无用的色彩的。

尺寸(dimen)

尽量遵循 Material Design 的设计标准,比如字体的大小,页面左右空白16dp,列表上下间隔8dp等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<resources>

<dimen name="horizontal_margin">16dp</dimen>
<dimen name="vertical_margin">16dp</dimen>
<dimen name="horizontal_padding">16dp</dimen>
<dimen name="vertical_padding">16dp</dimen>
<dimen name="fab_margin">16dp</dimen>

<!-- 页面统一间距 -->
<dimen name="title_height">48dp</dimen>
<dimen name="toolbar_height">48dp</dimen>
<dimen name="tab_height">48dp</dimen>
<dimen name="bar_height">56dp</dimen>
<dimen name="edittext_height">56dp</dimen>
<dimen name="caption_height">24dp</dimen>
<dimen name="line_height">8dp</dimen>
<dimen name="line_height_half">4dp</dimen>
<dimen name="line_height_double">16dp</dimen>
<dimen name="layout_height">72dp</dimen>

<!-- 字体大小 -->
<dimen name="text_display3">56sp</dimen>
<dimen name="text_display2">45sp</dimen>
<dimen name="text_display1">34sp</dimen>
<dimen name="text_headline">24sp</dimen>
<dimen name="text_title">20sp</dimen>
<dimen name="text_subhead">16sp</dimen>
<dimen name="text_body">14sp</dimen>
<dimen name="text_caption">12sp</dimen>
<dimen name="text_mini">10sp</dimen>
<dimen name="text_menu">14sp</dimen>
<dimen name="text_button">16sp</dimen>
<dimen name="text_navi">18sp</dimen>

</resources>

尽量不要直接在布局文件里面写上具体的数值。

字符串(string)

strings的name命名使用下划线命名法,采用以下规则:模块名+逻辑名称
同样,禁止在代码中或者layout中直接填入字符,请在string.xml加入字符串。最好是按模块来分隔开字符串便于查找和修改,公用的写在最开始位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<resources>
<string name="app_name">cpacm</string>

<string name="open_string">open</string>
<string name="close_string">close</string>

<!--#################### Home模块 #####################-->

<!-- bottom navi -->
<string name="free">休闲</string>
<string name="news">资讯</string>
<string name="beauty">风采</string>
<string name="study">学习</string>
<string name="contract">互动</string>

<!--##################### Free模块 #####################-->
<!-- tab -->
<string name="music">音乐</string>
<string name="movie">电影</string>
<string name="book">图书</string>

</resources>

所有文字放在 strings.xml 中可以很方便的转换多国语言。

样式(style)

style的name命名使用大驼峰命名法。
当某部分xml属性代码重复过多时,请将其变成 style 以便重复利用。

1
2
3
4
<style name="ContentText">
<item name="android:textSize">@dimen/font_normal</item>
<item name="android:textColor">@color/basic_black</item>
</style>

自定义属性(attr)

attr的name命名使用大驼峰命名法。
在自定义控件或其他地方需要自定义属性名称时,除去直接加入attrs.xml中也可以新建一个 attr 文件,并在 attr 后加上功能名称。
attr_slider 表示一个轮播器控件的自定义属性。

layout内的id命名

命名模式为:模块名_view缩写,比如 search_btn

注释

类注释

每个类都必须要写上

  1. 创建时间
  2. 作者
  3. 类的作用描述
  4. 版本和联系方式(可选)
    这样团队就能知道这个类的作用是什么,原生产者是谁。
1
2
3
4
5
6
7
8
9
10
11
12
/**
* <pre>
* author : cpacm
* e-mail : xxx@xx
* date : 2017/03/21
* description : xxxx描述
* version: 1.0
* </pre>
*/

public class MainActivity {
...
}

在 Android Studio 中 Settings → Editor → File and Code Templates → Includes → File Header,输入模板。

方法注释

每个成员方法都应该有一个头注释,告诉我们这个方法做了什么,返回了什么。

1
2
3
4
5
6
/**
* snackbar的显示
*/

public void showSnackBar(View view, @StringRes int toast) {
Snackbar.make(view, getString(toast), Snackbar.LENGTH_SHORT).show();
}

设置Fix doc comment(Settings → Keymap → Fix doc comment)快捷键,AS便会生成模板。

块/行注释

主要作用是为一些代码进行补充说明,防止自己或团队的其他人无法理解代码的含义。

1
2
//指向书城界面
viewPager.setCurrentItem(2, false);

总结

上面的规范只是给个参考,适合自己或团队才是最好的。养成好的命名习惯才能写出优美的代码,这需要长时间的坚持才能培养出来。说实话,其实英语基础才是最重要的XD.
Java 更多的编写风格可以参考:Google Java 命名规范


参考资料:

  1. Google Java 命名规范
  2. 安卓开发规范