参考文章:http://keeganlee.me/post/android/20150709 http://www.jianshu.com/p/0a984f999592
https://source.android.com/source/code-style
源文件结构规范
一个源文件包含(按顺序地):
- 许可证或版权信息(如有需要)
- package语句
- import语句
- 一个顶级类(只有一个)以上每个部分之间用一个空行隔开。
许可证或版权信息
如果一个文件包含许可证或版权信息,那么它应当被放在文件最前面。
package语句
package 语句不换行,列限制并不适用于package语句。(即package语句写在一行里)
import语句
import不要使用通配符
即,不要出现类似这样的import语句:import java.util.*;
不要换行
import语句不换行,列限制并不适用于import语句。(每个import语句独立成行)
顺序和间距
import语句可分为以下几组,按照这个顺序,每组由一个空行分隔:
- 导入 Android 包
- 导入第三方包(com、junit、net、org)
- java 和 javax
类声明
只有一个顶级
类声明每个顶级类都在一个与它同名的源文件中(当然,还包含.java后缀)。
类成员顺序
类的成员顺序对易学性有很大的影响,但这也不存在唯一的通用法则。不同的类对成员的排序可能是不同的。
最重要的一点,每个类应该以某种逻辑去排序它的成员,维护者应该要能解释这种排序逻辑。比如, 新的方法不能总是习惯性地添加到类的结尾,因为这样就是按时间顺序而非某种逻辑来排序的。
区块划分
建议使用注释将源文件分为明显的区块,区块划分如下
- 常量声明区
- UI控件成员变量声明区
- 普通成员变量声明区
- 内部接口声明区
- 初始化相关方法区
- 事件响应方法区
- 普通逻辑方法区
- 重载的逻辑方法区
- 发起异步任务方法区
- 异步任务回调方法区
- 生命周期回调方法区(出去onCreate()方法)
- 内部类声明区
重载:永不分离
当一个类有多个构造函数,或是多个同名方法,这些函数/方法应该按顺序出现在一起,中间不要放进其它函数/方法。
注释规范
文件头注释
文件头注释使用以下格式,需要将版权声明进行替换
/**
* Copyright (C) 2017 zhangyang. All rights reserved.
*
* @Package: ${PACKAGE_NAME}
* @Description:
* @author ${USER}
* @date ${TIME}
*/
在android studio中的配置方法为:
类和接口注释
类和接口的注释使用以下的注释格式:
/**
* @description $description$
* @author $user$
* @time $date$ $time$
*/
在android studio中的配置方式如下,首先选择Editor->Live Templates,然后选择右侧的加号,选择Template Group,命名为custom,再点击加号,选择Live Template,命名为cmc(cmc是快捷键,可以自己任意命名),然后可以对该自定义模板进行描述,并选择应用的场景为java->Declaration,详见下面的第二幅图。最后注意需要点击Edit variables,对相应的值配置由程序动态赋值,例如$user$,配置为user(),即使用当前计算机用户名,减少工作量。
方法注释
方法注释采用如下格式:
/**
* @description 用户注册
* @author zhangyang
* @time 2017/6/19 上午9:38
* @param userName 用户名
* @param password 密码
* @return
*/
public int registerUser(String userName, String password);
在android studio中的配置方式与上面的类和接口的配置方式相同:
/**
* @description $description$
* @author $user$
* @time $date$ $time$
* @param $param$
* @return $return$
*/
这里我命名快捷键为cmf。注意:在android studio里面没有找到自定义模板自动生成参数的方案,如果使用默认的方法生成注释方案,则除了参数不能增加其他的自定义字段。因此需要编写代码时,在相应方法上输入cmf生成注释后,还需要手动编辑@param,有几个参数需要编辑几个。
变量和常量注释
下面几种情况下的常量和变量,都要添加注释说明,在上方添加注释。//和内容后面有一个空格。
- 接口中定义的所有常量
- 公有类的公有常量
- 枚举类定义的所有枚举常量
- 实体类的所有属性变量
// 普通用户
public static final int TYPE_COMMON_USER = 1;
// 管理员用户
public static final int TYPE_ADMIN_USER = 2;
书写规范
编码方式
编码方式统一用UTF-8. Android Studio默认已是UTF-8,只要不去改动它就可以了。
缩进
缩进统一为4个空格
花括号书写
- 左大括号前不换行
- 左大括号后换行
- 右大括号前换行
- 如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行
例如,如果右大括号后面是else或逗号,则不换行。
return new MyClass() {
@Override public void method() {
if (condition()) {
try {
something();
} catch (ProblemException e) {
recover();
}
}
}
};
空格的使用
if、else、for、switch、while等逻辑关键字与后面的语句留一个空格隔开。
if (booleanVariable) {
// TODO while booleanVariable is true
} else {
// TODO else
}
运算符两边各用一个空格隔开。
int result = a + b; //Good, = 和 + 两边各用一个空格隔开
int result=a+b; //Bad,=和+两边没用空格隔开
方法的每个参数之间用一个空格隔开。
public void method(String param1, String param2); // Good,param1后面的逗号与String之间隔了一个空格
method(param1, param2); // Good,方法调用时,param1后面的逗号与param2之间隔了一个空格
method(param1,param2); // Bad,没有用一个空格隔开
空行的使用
将逻辑相关的代码段用空行隔开,以提高可读性。空行也只空一行,不要空多行。在以下情况需用一个空行:
- 两个方法之间
- 方法内的两个逻辑段之间
- 方法内的局部变量和方法的第一条逻辑语句之间
- 常量和变量之间
表达式过长书写
当一个表达式无法容纳在一行内时,可换行显示,另起的新行用8个空格缩进。
someMethod(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
变量声明
一行声明一个变量,不要一行声明多个变量,这样有利于写注释。
// 参数1
private String param1;
// 参数2
private String param2;
行宽设置
行宽设置为100,设置格式化时自动断行到行宽位置。
方法规模
一个方法最多不要超过40行代码(官方建议)。
常量定义
常量统一采用接口来定义,按模块和类型等划分。
文字和元素大小单位定义
官方建议文字大小的单位统一用sp,元素大小的单位统一用dp。从实际开发中看,文字大小采用sp,会导致文字大小随着系统设置字体的大小变化,导致布局出问题。因此我们项目组初期采用的都是使用dp,但目前使用的是以1280*720基准尺寸,横坐标分成1280份,纵坐标分成720份,其他按比例进行伸缩,实际是以px为单位处理。
字符串定义
应用中的字符串统一在strings.xml中定义,然后在代码和布局文件中引用。
颜色定义
颜色值统一在colors.xml中定义,然后在代码和布局文件中引用。另外,不要在代码和布局文件中引用系统的颜色,除了透明。
命名规范
包命名
域名反写+项目名称+模块名称,全部单词用小写字母。
例如
com.android.example.login
类和接口命名
使用大驼峰规则,用名词或名词词组命名,每个单词的首字母大写。
以下为几种常用类的命名:
- activity类,命名以Activity为后缀,如:LoginActivity
- fragment类,命名以Fragment为后缀,如:ShareDialogFragment
- service类,命名以Service为后缀,如:DownloadService
- adapter类,命名以Adapter为后缀,如:CouponListAdapter
- 工具类,命名以Util为后缀,如:EncryptUtil
- 模型类,命名以Model为后缀,如:LoginModel
- 接口实现类,命名以Impl为后缀,如:ApiImpl
方法命名
使用小驼峰规则,用动词命名,第一个单词的首字母小写,其他单词的首字母大写。
以下为几种常用方法的命名:
- 初始化方法,命名以init开头,例:initView
- 按钮点击方法,命名以onClick开头,例:onclickLogin
- 设置方法,命名以set开头,例:setData
- 具有返回值的获取方法,命名以get开头,例:getData
- 通过异步加载数据的方法,命名以load开头,例:loadData
- 布尔型的判断方法,命名以is或has,或具有逻辑意义的单词如equals,例:isEmpty
控件缩写
控件 | 缩写 | 控件 | 缩写 |
---|---|---|---|
TextView | TV | EditText | ET |
Button | Btn | ImageButton | IBt |
ImageView | IV | ListView | LV |
ProgressBar | PB | SeekBar | SB |
CheckBox | CB | LinearLayout | LL |
Relativelayout | RL | FrameLayout | FL |
ScrollView | SV | GridView | GV |
常量命名
全部为大写单词,单词之间用下划线分开。
public final static int PAGE_SIZE = 20;
变量命名
{范围描述+}意义描述+类型描述的组合,用驼峰式,首字母小写
- 非公开且非静态字段的名称以 m 开头。
- 静态字段的名称以 s 开头。
- 其他字段以小写字母开头。
- 公开静态 final 字段(常量)为全部大写并用下划线连接 (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;
}
控件id命名
控件缩写{范围}意义,范围可选,只在有明确定义的范围内才需要加上。
<!-- 这是标题栏的标题 -->
<TextView
android:id="@+id/tv_header_title"
... />
<!-- 这是登录按钮 -->
<Button
android:id="@+id/btn_login"
... />
layout命名
组件类型{范围}功能,范围可选,只在有明确定义的范围内才需要加上。
以下为几种常用的组件类型命名:
- activity_{范围_}功能,为Activity的命名格式
- fragment_{范围_}功能,为Fragment的命名格式
- dialog_{范围_}功能,为Dialog的命名格式
- item_list_{范围_}功能,为ListView的item命名格式
- item_grid_{范围_}功能,为GridView的item命名格式
- header_list_{范围_}功能,为ListView的HeaderView命名格式
- footer_list_{范围_}功能,为ListView的FooterView命名格式
strings的命名
模块类型{范围_}功能,范围可选。
以下为几种常用的命名(以登录模块为例):
- 页面标题,命名格式为:login_title_页面
- 按钮文字,命名格式为:login_btn_按钮事件
- 标签文字,命名格式为:login_label_标签文字
- 选项卡文字,命名格式为:login_tab_选项卡文字
- 消息框文字,命名格式为:login_toast_消息
- 编辑框的提示文字,命名格式为:login_hint_提示信息
- 图片的描述文字,命名格式为:login_desc_图片文字
- 对话框的文字,命名格式为:login_dialog_文字
- menu的item文字,命名格式为:login_action_文字
colors的命名
前缀{控件}{范围}{_后缀},控件、范围、后缀可选,但控件和范围至少要有一个。例如bg_btn_send_normal
- 背景颜色,添加bg前缀
- 文本颜色,添加text前缀
- 分割线颜色,添加div前缀
- 公共的颜色,添加common前缀
- 区分状态时,默认状态的颜色,添加normal后缀
- 区分状态时,按下时的颜色,添加pressed后缀
- 区分状态时,选中时的颜色,添加selected后缀
- 区分状态时,不可用时的颜色,添加disable后缀
drawable的命名
前缀{控件}{范围}{_后缀},控件、范围、后缀可选,但控件和范围至少要有一个。
- 图标类,添加ic前缀
- 背景类,添加bg前缀
- 分隔类,添加div前缀
- 默认类,添加def前缀
- 区分状态时,默认状态,添加normal后缀
- 区分状态时,按下时的状态,添加pressed后缀
- 区分状态时,选中时的状态,添加selected后缀
- 区分状态时,不可用时的状态,添加disable后缀
- 多种状态的,添加selector后缀(一般为ListView的selector或按钮的selector)
动画文件命名
动画类型_动画方向。
- fade_in,淡入
- fade_out,淡出
- push_down_in,从下方推入
- push_down_out,从下方推出
- slide_in_from_top,从头部滑动进入
- zoom_enter,变形进入
- shrink_to_middle,中间缩小
编程实践
@Override:能用则用
只要是合法的,就把@Override注解给用上。
捕获的异常:不能忽视
除了下面的例子,对捕获的异常不做响应是极少正确的。(典型的响应方式是打印日志,或者如果它被认为是不可能的,则把它当作一个 AssertionError 重新抛出。)
如果它确实是不需要在catch块中做任何响应,需要做注释加以说明(如下面的例子)。
try {
int i = Integer.parseInt(response);
return handleNumericResponse();
} catch (NumberFormatException ok) {
// it's not numeric; that's fine, just continue
}
return handleTextResponse(response);
例外:在测试中,如果一个捕获的异常被命名为expected,则它可以被不加注释地忽略。下面是一种非常常见的情形,用以确保所测试的方法会抛出一个期望中的异常,因此在这里就没有必要加注释。
try {
emptyStack.pop();
fail();
} catch (NoSuchElementException expected) {
}
使用 TODO 备注
为代码使用 TODO 备注是短期的临时解决方案,或者说足够好但并不完美。TODO 备注应该以全部大写的字符串 TODO 开头,后跟一个冒号:
// TODO: Remove this code after the UrlTable2 has been checked in.
和
// TODO: Change this to use a flag instead of a constant.
如果TODO 采用“在未来的某个日期做某事”的形式,请确保在其中包含一个非常具体的日期(“在 2005 年 11 月前修复”)或者一个非常具体的事件(“在所有生产环境合成器都可处理 V7 协议后移除此代码”)。
静态成员:使用类进行调用
使用类名调用静态的类成员,而不是具体某个对象或表达式。
Foo aFoo = ...;
Foo.aStaticMethod(); // good
aFoo.aStaticMethod(); // bad
somethingThatYieldsAFoo().aStaticMethod(); // very bad
Finalizers: 禁用
极少会去重载Object.finalize。
Tip:
不要使用finalize。如果你非要使用它,请先仔细阅读和理解Effective Java第7条款:"Avoid Finalizers",然后不要使用它。
谨慎使用日志记录
项目中请不要直接使用Log打印日志,应该至少对系统日志封装一个日志类,该类可以控制当前打印输出的日志级别或者打开和关闭日志打印。每个类定义一个常量TAG用来打印相应的类的日志,当功能开发稳定之后,请去掉开发打印的调试日志。
保持一致
总而言之:保持一致。如果正在修改代码,花几分钟时间看一下周围的代码并确定其样式。如果该代码在 if 语句周围使用空格,那么您也应该这样做。如果代码备注的周围是用星号组成的小方框,您也应该将备注放在这样的小方框内。